Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does ptr_vector manage memory?

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?

like image 816
polyclick Avatar asked Jul 26 '12 09:07

polyclick


2 Answers

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.

like image 72
pmr Avatar answered Nov 06 '22 18:11

pmr


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

like image 2
ForEveR Avatar answered Nov 06 '22 19:11

ForEveR