为struct动态分配内存

sir*_*isp 9 c++ struct dynamic

我正在学习一个C++类并且有一个赋值,它要求我为一个struct动态分配内存.我不记得曾经在课堂上讨论这个问题,我们在上课new之前只是简单地谈过了 算子.现在我必须

"动态分配学生,然后提示用户输入学生的名字,姓氏和A号码(身份证号码)."

我的结构写得像

struct Student
{
    string firstName, lastName, aNumber;
    double GPA;
};
Run Code Online (Sandbox Code Playgroud)

我尝试Student student1 = new Student;但是这不起作用,我不确定我是如何用结构动态地做这个的.

par*_*mar 15

将您的定义更改为

struct Student 
{
    string firstName, lastName, aNumber;
    double GPA;
};
Run Code Online (Sandbox Code Playgroud)

注意我已经更改了struct关键字的位置

而你必须做Student* student1 = new Student.

当您为结构动态分配内存时,您将获得指向结构的指针.

完成学生后,您还必须记住通过执行a释放动态分配的内存delete student1.您可以使用std :: shared_ptr自动管理动态分配的内存.

  • @sircrisp听起来像你真的需要咨询你的课程材料.或者[好的C++书籍](http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list).你需要使用` - >`来通过指针访问成员. (3认同)
  • @sircrisp这是_exactly_ what"unique_ptr"的作用.除了它为你做.不要使用原始指针,他们很糟糕. (2认同)
  • @sircrisp:从这个问题来看,这_不是_你学习的方式。 (2认同)

Pup*_*ppy 7

这应该是你需要的:

std::unique_ptr<Student> x(new Student);
Run Code Online (Sandbox Code Playgroud)

  • 废话.很大程度上取决于应用程序,但大多数指针应该是原始指针.(就此而言,你无法避免它,因为`this`是一个原始指针.)`unique_ptr`具有非常特定的语义; 当你需要那些语义时,它是优秀的,但是当你不需要时,使用它是一个错误.由于我们不知道他为什么动态分配(我怀疑事实上,他根本不应该使用动态分配),我们不能对"unique_ptr"的适当性作出任何假设. (2认同)

Che*_*Alf 5

"动态分配学生,然后提示用户输入学生的名字,姓氏和A号码(身份证号码)."

此分配要求您拥有一个未完全初始化的Student对象,直到您可以使用用户提供的信息更新它.一般来说这是一个非常糟糕的想法,因为仅具有未完全初始化对象的可能性(例如,在这种情况下缺少正确的id值)使得使用该对象的代码更复杂,因为它必须检查例如是否存在是一个正确的id值.正确使用的复杂性,以及未能认识到正确使用所需的复杂性,吸引了疯狂的错误.

这就是扩展C的C++ 在分配和初始化之间提供了非常强大的耦合的原因.使用C++ new表达式,您可以获得成功的分配,也可以获得成功的完整初始化,或者两者都没有(它会在失败时清除).这就是问题应该更好的教导!

因此,除了上面引用的给定问题,我将教你可接受的C++实践(尽管new通常要避免使用),这意味着回答这个修改过的问题:

提示用户输入学生的名字,姓氏和A号码(ID号),然后Student使用这些值动态分配对象.

好的,这里是:

// The Dynamic Student, version 1.
// "Prompt the user for student’s first name, a last name, and A - number
// (ID), and then dynamically allocate a `Student` object with these values."

#include <assert.h>         // assert
#include <iostream>         // std::cout,std::endl
#include <string>           // std::string
#include <sstream>          // std::istringstream
#include <stdexcept>        // std::exception, std::runtime_error
#include <stdlib.h>         // EXIT_SUCCESS, EXIT_FAILURE

#define CPP_NO_COPYING_OF( Clazz )      \
    Clazz( Clazz const& );              \
    Clazz& operator=( Clazz const& )

namespace cpp {
    using namespace std;

    bool hopefully( bool const c ) { return c; }
    bool throwX( string const& s ) { throw runtime_error( s ); }

    string lineFromInput()
    {
        string result;
        getline( cin, result )
            || throwX( "lineFromInput: std::getline failed (EOF?)" );
        return result;
    }

    string lineFromInput( string const& prompt )
    {
        cout << prompt;
        return lineFromInput();
    }

    int intFromInput( string const& prompt )
    {
        istringstream   stream( lineFromInput( prompt ) );
        int             result;

        stream >> result
            || throwX( "intFromInput: input line was not a valid number spec" );
        return result;
    }
}  // namespace cpp

namespace blah {
    using namespace std;
    using namespace cpp;

    struct Student
    {
        CPP_NO_COPYING_OF( Student );

        int const       id;
        string const    firstName;
        string const    lastName;

        Student(
            int const       _id,
            string const    _firstName,
            string const    _lastName
            )
            : id( _id ), firstName( _firstName ), lastName( _lastName )
        {}
    };

    Student* studentFromInput()
    {
        cout << "It's -- the Dynamic Student program!" << endl;

        string const    firstName   = lineFromInput( "First name, please? " );
        hopefully( firstName != "" )
            || throwX( "Sorry, the first name can't be nothing." );

        string const    lastName    = lineFromInput( "Last name, please? " );
        hopefully( lastName != "" )
            || throwX( "Sorry, the last name can't be nothing." );

        int const       id          = intFromInput( "And the student id is...? " );
        hopefully( id > 0 )
            || throwX( "Sorry, the id can't be negative or zero." );

        return new Student( id, firstName, lastName );
    }
}  // namespace blah

void cppMain()
{
    using namespace blah;

    Student const* const    pStudent    = studentFromInput();

    try
    {
        // Use the student object, e.g.
        cout
            << "The student is "
            << pStudent->firstName << " " << pStudent->lastName
            << ", with id " << pStudent->id << "."
            << endl;
        // Then:
        delete pStudent;
    }
    catch( std::exception const& )
    {
        delete pStudent;
        throw;      // Rethrows the exception.
    }
}

int main()
{
    using namespace std;

    try
    {
        cppMain();
        return EXIT_SUCCESS;
    }
    catch( exception const& x )
    {
        cerr << "!" << x.what() << endl;
    }
    return EXIT_FAILURE;
}
Run Code Online (Sandbox Code Playgroud)

对于每个执行的new表达式(执行分配和初始化),理想情况下应该是delete表达式的相应执行,它清理并释放内存块以便可以重用它.delete理想情况下,即使某些内容失败也会执行该表达式并抛出异常.因此trycatch.

但是,像这样编码是容易出错和冗长的.

相反,在更惯用的C++编程一个将使用一个智能指针,保存一个指针,并提供指针操作(所以它看起来像一个对象一个指针),其析构函数自动执行一个delete当指针不再使用的表达.C++标准库有几个这样的智能指针类.作为一般规则,使用最严格的智能指针,因为它具有最小的开销,并且很可能支持转换为更一般的智能指针,而相反的可能性则小得多,不太可能.

所以在这种情况下,您可以使用例如C++ 11 std::unique_ptr或者如果您的编译器是旧的,C++ 03 std::auto_ptr,来自<memory>标题:

// The Dynamic Student, version 2  --  using smart pointer.
// "Prompt the user for student’s first name, a last name, and A - number
// (ID), and then dynamically allocate a `Student` object with these values."

#include <assert.h>         // assert
#include <iostream>         // std::cout,std::endl
#include <memory>           // std::unique_ptr
#include <string>           // std::string
#include <sstream>          // std::istringstream
#include <stdexcept>        // std::exception, std::runtime_error
#include <stdlib.h>         // EXIT_SUCCESS, EXIT_FAILURE

#define CPP_NO_COPYING_OF( Clazz )      \
    Clazz( Clazz const& );              \
    Clazz& operator=( Clazz const& )

namespace cpp {
    using namespace std;

    bool hopefully( bool const c ) { return c; }
    bool throwX( string const& s ) { throw runtime_error( s ); }

    string lineFromInput()
    {
        string result;
        getline( cin, result )
            || throwX( "lineFromInput: std::getline failed (EOF?)" );
        return result;
    }

    string lineFromInput( string const& prompt )
    {
        cout << prompt;
        return lineFromInput();
    }

    int intFromInput( string const& prompt )
    {
        istringstream   stream( lineFromInput( prompt ) );
        int             result;

        stream >> result
            || throwX( "intFromInput: input line was not a valid number spec" );
        return result;
    }
}  // namespace cpp

namespace blah {
    using namespace std;
    using namespace cpp;

    struct Student
    {
        CPP_NO_COPYING_OF( Student );

        int const       id;
        string const    firstName;
        string const    lastName;

        Student(
            int const       _id,
            string const    _firstName,
            string const    _lastName
            )
            : id( _id ), firstName( _firstName ), lastName( _lastName )
        {}
    };

    unique_ptr<Student> studentFromInput()
    {
        cout << "It's -- the Dynamic Student program!" << endl;

        string const    firstName   = lineFromInput( "First name, please? " );
        hopefully( firstName != "" )
            || throwX( "Sorry, the first name can't be nothing." );

        string const    lastName    = lineFromInput( "Last name, please? " );
        hopefully( lastName != "" )
            || throwX( "Sorry, the last name can't be nothing." );

        int const       id          = intFromInput( "And the student id is...? " );
        hopefully( id > 0 )
            || throwX( "Sorry, the id can't be negative or zero." );

        return unique_ptr<Student>( new Student( id, firstName, lastName ) );
    }
}  // namespace blah

void cppMain()
{
    using namespace blah;

    unique_ptr<Student> const   pStudent    = studentFromInput();

    // Use the student object, e.g.
    cout
        << "The student is "
        << pStudent->firstName << " " << pStudent->lastName
        << ", with id " << pStudent->id << "."
        << endl;
}

int main()
{
    using namespace std;

    try
    {
        cppMain();
        return EXIT_SUCCESS;
    }
    catch( exception const& x )
    {
        cerr << "!" << x.what() << endl;
    }
    return EXIT_FAILURE;
}
Run Code Online (Sandbox Code Playgroud)

但是,除了赋值使用动态分配的要求外,具有上述功能的程序将在没有任何动态分配或智能指针的情况下编写.该studentFromInput函数只是Student按值返回一个对象,复制.这几乎是一个悖论,但现代C++非常依赖于复制,并且仍然可以生成相当快的程序!

当然,在引擎盖下有大量的肮脏技巧,以避免复制实际发生在机器代码中.