C++ 为struct动态分配内存

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9397288/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 12:47:10  来源:igfitidea点击:

Dynamically allocate memory for struct

c++dynamicstruct

提问by sircrisp

I am taking a C++ class and have a assignment which requires me to dynamically allocate memory for a struct. I don't recall ever going over this in class and we only briefly touched on the newoperator before going on to classes. Now I have to

我正在学习一个 C++ 类,并且有一个任务需要我为结构动态分配内存。我不记得曾经在课堂上讨论过这个,我们在上课new之前只是简单地接触过 操作符。现在我必须

"Dynamically allocate a student and then prompts the user for student's first name, a last name, and A - number(ID number). "

“动态分配一个学生,然后提示用户输入学生的名字、姓氏和A-number(ID号)。”

my struct is written like

我的结构是这样写的

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

I tried Student student1 = new Student;but that doesn't work and I'm unsure as how I do this dynamically with a struct.

我试过了,Student student1 = new Student;但这不起作用,我不确定我是如何用结构动态地做到这一点的。

回答by parapura rajkumar

Change you definition to

将您的定义更改为

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

Notice I have changed the placement of the struct keyword

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

and you have to do Student* student1 = new Studentinstead.

而你必须这样做Student* student1 = new Student

When you dynamically allocated memory for a struct you get a pointer to a struct.

当您为结构动态分配内存时,您会得到一个指向结构的指针。

Once you are done with the Studentyou also have to remember to to release the dynamically allocated memory by doing a delete student1. You can use a std::shared_ptrto manage dynamically allocated memory automatically.

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

回答by Puppy

This should be what you need:

这应该是你需要的:

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

回答by Cheers and hth. - Alf

"Dynamically allocate a student and then prompts the user for student's first name, a last name, and A - number(ID number). "

“动态分配一个学生,然后提示用户输入学生的名字、姓氏和A-number(ID号)。”

This assignment requires you to have a not completely initialized Studentobject around until you can update it with the information provided by the user. That is a very bad idea in general, because the mere possibility of having a not completely initialized object (e.g. in this case lacking a proper id value) makes the code using that object more complex because it has to check whether, for example, there is a proper id value. And that complexity for proper use, plus failures to recognize that the complexity is needed for proper use, attracts bugs like mad – ungood.

此分配要求您有一个未完全初始化的Student对象,直到您可以使用用户提供的信息对其进行更新。一般来说,这是一个非常糟糕的主意,因为仅仅有一个未完全初始化的对象(例如,在这种情况下缺少正确的 id 值)的可能性会使使用该对象的代码变得更加复杂,因为它必须检查是否存在,例如是一个正确的 id 值。而正确使用的复杂性,加上未能认识到正确使用需要复杂性,会吸引像疯子这样的错误 - 不好。

That is why C++, extending C, provided a very strong couplingbetween allocation and initialization. With a C++ newexpression you get either botha successful allocation and a successful complete initialization, or else neither (it cleans up on failure). That is what the question should better teach!

这就是为什么扩展 C 的 C++在分配和初始化之间提供了非常强的耦合。对于C ++new表达式你要么成功的分配和成功完成初始化,否则没有(它失败清理)。这就是问题应该更好地教导的!

So instead of the given question quoted above, I'm going to teach you acceptable C++ practice (although using newis generally to be avoided), which means answering this modified question:

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

Prompt the user for student's first name, a last name, and A - number(ID number), and then dynamically allocate a Studentobject with these values.

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

OK, here goes:

好的,这里是:

// 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;
}

For each executed newexpression (which does allocation and initialization) there should ideally be a corresponding execution of a deleteexpression, which cleans up and deallocates the memory block so that it can be reused. And the deleteexpression should ideally be executed even if something fails and throws an exception. Hence the tryand catch.

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

However, coding it like that is error prone and verbose.

但是,像这样编码很容易出错且冗长。

Instead, in more idiomatic C++ programming one will use a smart pointer, an object that holds a pointer and provides pointer operations (so it looks like it isa pointer), and whose destructor automatically executes a deleteexpression when the pointer is no longer used. The C++ standard library has several such smart pointer classes. As a general rule, use the most restrictive smart pointer that you can, because it has least overhead and will most likely support conversion to more general smart pointers, while the opposite is much less likely, downright unlikely.

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

So in this case, you can use e.g. C++11 std::unique_ptror if your compiler is old, C++03 std::auto_ptr, both from the <memory>header:

所以在这种情况下,你可以使用例如 C++11std::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;
}

But, except for the assignment's requirement to use dynamic allocation, a program with the functionality above would be written without any dynamic allocation or smart pointers. The studentFromInputfunction would just return a Studentobject by value, copying. It is almost a paradox, but modern C++ is very heavily based on copying, and still yields pretty fast programs!

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

Of course, under the hood there are a large number of dirty tricks to avoid that the copying actuallyhappens in the machine code.

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

回答by James Kanze

Why are you using new? Just declare an instance of the variable:

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

Student student1;

Given the definition of Student, it doesn't look like it has identity, and it is certainly copyable, so you should probably never newit.

鉴于 的定义Student,它看起来没有身份,而且它肯定是可复制的,因此您可能永远不应该使用new它。

(I'd also provide it with a constructor, so that it can be initialized correctly from the moment it is defined.)

(我还会为它提供一个构造函数,以便从它被定义的那一刻起就可以正确地初始化它。)

回答by Jonathan Grynspan

structgoes before the name of the structure it defines. :)

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

What is the error you're seeing when you try new Student? Why doesn't it work?

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

回答by Mike Corcoran

new returns a pointer to an object... so you'd want

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

struct Student* student1 = new Student;

回答by Ade YU

The newstatement returns a pointer to the newed instance. So you need to defined the student1as a pointer.

new语句返回一个指向newed 实例的指针。所以你需要将 定义student1为一个指针。

struct Student * student1 = new Student;