Dynamically allocate memory for struct

谁都会走 提交于 2019-12-21 04:07:04

问题


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 new operator before going on to classes. Now I have to

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

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.


回答1:


Change you definition to

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

Notice I have changed the placement of the struct keyword

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

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

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




回答2:


This should be what you need:

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



回答3:


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

This assignment requires you to have a not completely initialized Student object 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.

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

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

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

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 new expression (which does allocation and initialization) there should ideally be a corresponding execution of a delete expression, which cleans up and deallocates the memory block so that it can be reused. And the delete expression should ideally be executed even if something fails and throws an exception. Hence the try and catch.

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 is a pointer), and whose destructor automatically executes a delete expression 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.

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

// 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 studentFromInput function would just return a Student object by value, copying. It is almost a paradox, but modern C++ is very heavily based on copying, and still yields pretty fast programs!

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




回答4:


struct goes before the name of the structure it defines. :)

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




回答5:


The new statement returns a pointer to the newed instance. So you need to defined the student1 as a pointer.

struct Student * student1 = new Student;



回答6:


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

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 new it.

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




回答7:


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

struct Student* student1 = new Student;


来源:https://stackoverflow.com/questions/9397288/dynamically-allocate-memory-for-struct

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!