Reputation:
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
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:
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
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
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
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:
For example:
class University{
Student s;
public:
University(){}
void addStudent(const Student& newStudent){
s = newStudent;
}
};
Upvotes: -1