为struct动态分配内存

时间:2012-02-22 15:03:46

标签: c++ dynamic struct

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

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

我的结构写得像

struct Student
{
    string firstName, lastName, aNumber;
    double GPA;
};

我尝试了Student student1 = new Student;但是这不起作用,我不确定我是如何使用结构动态执行此操作的。

8 个答案:

答案 0 :(得分:13)

将您的定义更改为

struct Student 
{
    string firstName, lastName, aNumber;
    double GPA;
};

请注意,我已更改struct关键字的位置

而你必须改为Student* student1 = new Student

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

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

答案 1 :(得分:7)

这应该是你需要的:

std::unique_ptr<Student> x(new Student);

答案 2 :(得分: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;
}

对于每个执行的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;
}

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

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

答案 3 :(得分:1)

struct在它定义的结构名称之前。 :)

当您尝试new Student时,您看到的错误是什么?为什么不起作用?

答案 4 :(得分:1)

new返回指向对象的指针...所以你想要

struct Student* student1 = new Student;

答案 5 :(得分:1)

new语句返回指向new ed实例的指针。因此,您需要将student1定义为指针。

struct Student * student1 = new Student;

答案 6 :(得分:1)

您为什么使用new?只需声明变量的实例:

Student student1;

鉴于Student的定义,它看起来不具有身份, 它肯定是可复制的,所以你可能永远不会new它。

(我还提供了一个构造函数,以便可以初始化它 从定义的那一刻开始正确。)

答案 7 :(得分:0)

如果您想了解语法的概念或想要使用该语法,请始终对待此getValues()语法。 作为结构学生=新的sizeof(学生);意味着您只需将数据类型放入sizeof()-fn中以进行大小确认。