tags:

views:

50

answers:

4

Into a class constructor, I need to create some objects on the fly and add them to a vector. Here is my code:

ContainerClass::ContainerClass() {
   for (int i = 0; i < limit; i++)
      elements.push_back(SubElement());
}

Is this the same thing with new SubElement()? Do I still need to free those SubElement() objects into the ContainerClass destructor?

+6  A: 

Method 1:

If you have std::vector<SubElement> elements;
Then you would use elements.push_back(SubElement()).

SubElement() creates a SubElement on the stack and then a copy gets added to the vector.

You should NOT call delete on the individual elements of the vector. They will be destructed and deallocated when the vector goes out of scope.

Method 2:

If you have std::vector<SubElement*> elements;
Then you would use elements.push_back(new SubElement()).

new SubElement() creates a SubElement on the heap, and then the address of that element gets stored in the vector.

You would need to call delete on the individual elements before the vector goes out of scope, otherwise you'll create a memory leak. They will be destructed and deallocated only when you call delete on each of the elements.

Brian R. Bondy
Thank you Brian, it was very helpful.
pocoa
+1  A: 

SubElement(): automatically allocated, new SubElement(): dynamically allocated.

Rule of thumb: you don't need to delete an object that wasn't created with new.

Etienne de Martel
So elements vector will be deleted automatically, so automatically created SubElement objects will also be deleted because there will not be any reference to them?
pocoa
When the vector is destroyed, it invokes the destructor of every object stored in it and frees its memory. However, if you use new, then you store pointers in your vector, not objects, so it will be the pointers' destructor which will be invoked (essentially doing nothing).
Etienne de Martel
+1  A: 

No - they are different.

Just SubElement() creates an automatic (stack) object that should be copied in order to be saved.

new SubElement() creates a dynamically allocated object on the heap, and should be assigned to a pointer to such an object. It must be released eventually, to prevent a memory leak.

Eli Bendersky
+1  A: 

It is not the same thing. In most object-oriented languages, particularly ones with built in garbage collection of any kind, all objects are allocated on the heap and variables always contain a pointer to the object, not the object itself.

C++ is one of the few object-oriented languages where you can refer to an object by value.

In the case of new you are creating an object and being given a pointer to it. You will then reference the object through the pointer and not directly. In the other case you are creating the object on the stack and the container will be storing its own copies.

Frequently, stack based copies will be referred to by reference (the whole idea behind & as a type qualifier), but those references are understood to generally be short-lived and a copy is usually made of the thing being referenced if that thing needs to be stored for awhile.

In this case in particular, if you have a container of pointers (i.e. ::std::vector<SubElement *> c) it stores pointers to objects and you would typically allocate them with new. But the standard library container classes (and most other container classes) do not delete pointers for you. They do not take 'ownership' of the pointer. So you will be responsible for deleting them yourself.

If you have a container of objects (i.e. ::std::vector<SubElement> c) then you would use the c.push_back(SubElement()) form and the container would store copies of the temporaries you were creating. The container does take ownership of those copies, and will also frequently copy them around internally. That's why objects you store by value in a container need to implement the copy constructor.

There is a way to get a container to take ownership of the pointers, but only indirectly. You can have the container store copies of objects that themselves take ownership. The standard class people use for this is ::std::tr1::shared_ptr<T>. Your container declaration would look like: ::std::vector< ::std::tr1::shared_ptr<SubElement> > c. You could then do: c.push_back(new SubElement()); and the container would delete the SubElement objects when it was done.

You should read up on shared_ptr and really understand what it's doing before you use it though.

Omnifarious