user4005913
user4005913

Reputation:

Using automatic variables in C++ Constructor

So I have read that using new means that you manually have to manage the memory while using automatic variables means that it will get deleted when the variable goes out of scope. How does this work with constructors? If I create an object using an automatic variable, will it be saved or not?

For example, if i have a class:

class University{
    Student s;
public:
    University(int id, char* name){
        Student x(id, name);
        s = x;
    }
};

Would this work? (Assuming I had a properly defined copy constructor for the class Student). If this does work, why would anyone want to use new over this? I'm very new to C++ so apologies if this is a stupid question.

Upvotes: 1

Views: 668

Answers (4)

πάντα ῥεῖ
πάντα ῥεῖ

Reputation: 1

Would this work?

Yes, it would work, but the indirection via x using

Student x(id, name);
s = x;

in the constructors body, is completely unnecessary! What I would do, just to condense constructors body code, and avoid reference initialization problems, is using the member initializer list:

class University{
    Student s;
public:
    University(int id, char* name) : s(id,name) {
                                // ^^^^^^^^^^^^ Use member initializer list!
    }
}; 

You don't need that intermediary instance in the constructors body.

If this does work, why would anyone want to use new over this?

There's no certain way to tell, IMHO. Sometimes for certain use cases/requirements it might be desirable to create instances of Student on the heap, rather than use a stack allocated instance.


ATTENTIVELY NOTE:

All of that you have posted here, looks very wrong from a semantical point of view though :-/ ...

A University usually has many Student's subscribed, not just a single one! That means you'll somehow need to keep a list of students within your University instance.
You better should consider to have something like

class University {
    std::vector<Student> students_;
    std::string universityName_;
public:
    University(std::string universityName) : universityName_(universityName) {}
    void addStudent(const Student& newStudent) {
       students_.push_back(newStudent);
    }
    void addStudent(int id, const char* name) {
       students_.push_back(Student(id,name));
    }
};

Upvotes: 3

Petr Skocik
Petr Skocik

Reputation: 60058

The naive interpretation of your code is that x is an automatic object on the stack of the University(...) constructor. When the constructor call ends, the x object gets destroyed. You're, however, also assigning the x object to s and s is declared as a member variable of the University objects, which will, naively speaking, preserve it.

(Unless the = operator is redefined for the Student class to do something unusual).

If you use the recommended initializer list

University(int id, char* name)
    : s(id, name)
{
}

, the semantics will be different in that that s will be constructed directly from (id, name). If you assign it like you do, then s will get first constructed with its default constructor if it has one, then assigned to from the x variable.

Upvotes: 1

Remy Lebeau
Remy Lebeau

Reputation: 595971

Yes, it works. s gets default-constructed first, then copy-assigned only if x is successfully constructed. If an exception is raised and it escapes the University constructor, both s and x are destructed if they were successfully constructed.

That being said, the best way to write this is to not create x at all, and initialize s in the University constructor's initialization list instead:

class University
{
private:
    Student s;

public:
    University(int id, char* name)
        : s(id, name)
    {
    }
};

That being said, your question is about new. The equivalent would look like this:

class University
{
private:
    Student *s;

public:
    University(int id, char* name)
        : s(new Student(id, name))
    {
        try
        {
            // do something that might throw an exception
        }
        catch (...)
        {
            delete s;
            throw;
        }
    }

    ~University()
    {
        delete s;
    }
};

The reason for the try/catch is because if the constructor throws an exception, the destructor will NOT be called.

The above can be replaced with the following using an automatic variable:

class University
{
private:
    std::auto_ptr<Student> s; // or std::unique_ptr if you are using C++11

public:
    University(int id, char* name)
        : s(new Student(id, name))
    {
    }
};

Regardless of whether an exception is thrown, s will be destructed if it was successfully constructed.

Upvotes: 4

ventsyv
ventsyv

Reputation: 3532

Yes, that will work. You are creating a temporary student, which is then copied into s, the student object that's member of the university class. As long as the instance of the university class is available, its members are also available. Here are a couple of pointers to make your program better:

  1. Use std::string instead of char*
  2. Passing a student object in the university constructor makes no sense, adding an addStudent method is a better approach in my opinion
  3. Pass const object reference, not primitives, it's better style (more encapsulated) and more efficient because of the reference

For example:

class University{
    Student s;
public:
    University(){}
    void addStudent(const Student& newStudent){
        s = newStudent;
    }

};

Upvotes: -1

Related Questions