I'm currently getting myself into c++ for lower level coding with opengl. I come from a heavy objc background so I have some understanding about memory management but I can't seem to get how the "boost" library manages container types like ptr_vector
.
I think my problem is related to the fact that I have no idea how ptr_vector
manages the destruction of itself and its objects.
Please take a look at the following code:
// Header file
...
ptr_vector<IObject3D> objects;
...
// Implementation file
...
void ApplicationEngine::init()
{
WavefrontObject3D *object = new WavefrontObject3D("Ninja.obj");
objects.push_back(object);
}
...
So, for the actually question: am I creating a leak here through the "object" variable?
I'm used to retain and release my objects manually with explicit calls in objc:
previously I had to alloc init
the WavefrontObject3D object
, add it to an array and afterwards release
that same object to avoid leaks.
But when I add a delete object
after the push_back
call the deconstructor of the WavefrontObject3D object
is called. This gives me a hint that the ptr_vector
isn't retaining the object
variable. Is my assumption correct?
Additional, but related, question: let's say I want to destroy the containing class ApplicationEngine
don't I have to call some kind of deconstructor on the ptr_vector
or the elements it manages?
No, this doesn't create a leak. All ptr_*
containers will delete objects that are stored in them when the container goes out of scope.
If you delete the object after adding it to the container, you will create undefined behavior
as the container will attempt to delete it again.
Additional question: No, if you store the ptr_vector
by value its lifetime is managed by the scope of the surrounding class.
Let's write a simple implementation of ptr_vector
. It has no support for indirect iterators and custom deleters and a lot of other things but shows the principles used.
template <typename T>
class ptr_vector {
public:
// assume control over it
void push_back(T* x)
{ if(x) c_.push_back(x); else throw bad_pointer(); }
~ptr_vector() {
// delete everything that is stored here
for(auto x : c_) delete x;
}
private:
std::vector<T*> c_;
};
// a user class
struct user_class {
void addSomething() { x.push_back(new int(23)); }
ptr_vector<int> x;
};
If user class goes out of scope, the destructor of ptr_vector
will
be called and all memory will be reclaimed. No leak in sight.
void push_back( T* x );
Requirements: x != 0 Effects: Inserts the pointer into container and
takes ownership of it Throws: bad_pointer if x == 0 Exception safety:
Strong guarantee
template
<
class T,
class CloneAllocator = heap_clone_allocator,
class Allocator = std::allocator<void*>
>
class ptr_vector : public ptr_sequence_adapter
<
T,
std::vector<void*,Allocator>,
CloneAllocator
>
So you can specify your own CloneAllocator
and not delete elements that stored in ptr_vector, but heap_clone_allocator
(default par for CloneAllocator
) deletes all stored elements in destructor.
http://www.boost.org/doc/libs/1_50_0/libs/ptr_container/doc/reference.html#class-heap-clone-allocator
ptr_vector
will free all the elements in its destructor, so you don't have to do anything more than what you already do, that is, create the objects, add them to the ptr_vector
, and leave the management to it. Calling delete
explicitly will make the object destroyed twice (once when you request it and again when the ptr_vector
finishes). In other words, ptr_vector
does not duplicate the object.
When the ApplicationEngine
finishes, if it has an instance of the ptr_vector
, the destructor of that vector will be called, that in turn deletes the added objects.
ptr_containers own the memory pointed at by the pointer you pass to it.
Read the docs for more info on cloneable concepts.