Reputation: 33
For a programming assignment, we are given a template class with two members declared not as pointers, but actual objects:
Foo member;
In the constructor, I tried member = *(new Foo());
initially, but learned that, at least sometimes, it was copying the new Foo object, and therefore causing memory leaks.
I finally discovered member = Foo()
, and then looked up what the difference was. I learned that member will be allocated on the stack instead of the heap, and that it will be deleted once it is out of scope. How does this work for objects, though?
Is member only deleted when the parent / class object is deleted?
I also have another question about member = *(new Foo());
. I was initializing two member variables of the same type:
// Members
Foo member1;
Foo member2;
// Constructor {
member1 = *(new Foo());
member2 = *(new Foo());
}
For some reason it seemed member1
was not being copied and it retained the same address as the initial Foo
(i.e. there was no memory leak when it was deleted). member2
however, would be copied and had a different address, and memory was leaked. Is there an explanation for this?
Upvotes: 3
Views: 1616
Reputation: 95489
Your analysis is incorrect. Both of these are memory leaks. What you are doing is allocating a new copy of the object, assigning the value to the member, and then discarding the pointer to the allocated memory without freeing that memory. It is a memory leak in both cases.
Now, consider the following code:
class MemberType {
public:
MemberType() { std::cout << "Default constructor" << std::endl; }
MemberType(int) { std::cout << "Int constructor" << std::endl; }
};
class Example1 {
public:
Example1() {}
private:
MemberType member_;
};
class Example2 {
public:
Example2() : member_(5) {}
private:
MemberType member_;
};
int main(int argc, char** argv) {
Example1 example1;
Example2 example2;
return 0;
}
This code will print both different types of constructors. Note that it did not take any initialization code at all for the member to be initialized in the default manner. Hence your new statement (or even an assignment without new) would be unnecessary in the default initialization case. When initializing members using a constructor other than the default constructor, the proper way to do this is with an initializer list. (The initializer list is what is happening with ": member_(5)" in the example.
Please see the C++ FAQ on constructors for more information about constructing objects in C++.
Upvotes: 5
Reputation: 355039
member = *(new Foo());
new Foo()
dynamically allocates a Foo
object and returns a pointer to that object. The *
dereferences that pointer, giving you the Foo
object. This object is then assigned to member
, which involves calling the Foo
copy assignment operator. By default, this operator assigns the values of each of the members of the right-hand side (the *(new Foo())
) object into the left-hand side object (the member
).
The problem is this: new Foo()
dynamically allocates a Foo
object and that object is not destroyed until you delete
the pointer returned from the new
. You don't save that pointer anywhere, so you've leaked the dynamically allocated object.
This is not the correct way to initialize an object.
member = Foo();
This creates a temporary, initialized Foo
object and this object is assigned to member
. At the end of this statement (at the ;
, effectively), the temporary object is destroyed. member
is not destroyed, and the contents of the temporary Foo
object were copied into member
, so this is exactly what you want to do.
Note that the preferred way to initialize member variables is using the initializer list:
struct C {
Foo member1, member2;
C() : member1(), member2() { }
};
Upvotes: 2