Reputation: 908
I'm trying to save objects in an stl container (in this case a vector) and want the container to destroy the objects at its destruction, but I can't quite figure out the details.
One way I don't want to do it is simply using it like
vector<MyClass> myVec;
myVec.push_back(MyClass(...));
due to the fact that the constructor here is called twice (once in above code, then copy constructor in vector) and the destructor once.
The most direct alternative is to use pointers to store dynamically allocated objects, but then the destructor of MyClass won't be called at vector destruction. Storing auto_ptr instead of normal pointers gives an error at myVec.push_back(...).
Is there anyway to avoid the first option while having the container's destructor call the elements' destructor?
Thank you for your answers!
EDIT
Consider the similar problem; how to implement a container owning objects using an abstract base class. Unique pointer (Boost's unique_ptr) don't have copy constructors so one can't use that directly.
class A {}; // Abstract base class.
class B : public A {}; // Sub class.
...
vector<A *> vec;
vec.push_back(new B());
// At destruction of vec, destroy elements left in container.
Upvotes: 4
Views: 1496
Reputation: 29199
An alternative not already mentioned is the Boost Pointer Container Library.
Boost.Pointer Container provides containers for holding heap-allocated objects in an exception-safe manner and with minimal overhead. The aim of the library is in particular to make OO programming easier in C++ by establishing a standard set of classes, methods and designs for dealing with OO specific problems
With a boost::ptr_vector
, instead of pushing back copies, you push pointers to dynamically allocated objects. The ptr_vector
takes ownership of these objects and ensures that they are deleted when the ptr_vector
itself is deleted. Clients that read from the ptr_vector
use the same interface as a regular std::vector
, so they don't have to deal with pointers. For example, boost::ptr_vector<T>::front()
returns a reference.
The Motivation section of the documentation will help you decide if this is the right solution for you.
Upvotes: 4
Reputation: 264331
If you want to store pointers I like boost::ptr_vector
This acts like vector but stores and takes ownership of pointers.
The advantage of boost::ptr_vector<X>
over std::vector<some_smart_ptr<X>>
is that element access on the ptr_vector
returns a reference to the object rather than a reference to a (smart) pointer. This makes using the container with standard algorithms easier (as you do not need to bind a functor to dereference the element).
But unless there is a very good reason it is still best to store the object by value in a normal std::vector
.
Good reason may include:
Upvotes: 1
Reputation: 206508
The best possible way is to use elements by value in Standard Library containers.
Standard Library containers work on value semantics. i.e: they store elements by value and You know for sure that the container takes the ownership of the elements. So you do not need an explicit manual memory management.
As long as you obey the Rule of Three, the calling of copy constructor and destructor when storing elements by value should not be a problem for you.
In case of pointer as container elements you have to manually manage the memory and explicitly de-allocate the dynamic allocation.
In this case where You need the object to reside in dynamic memory, You should use Smart pointers.
auto_ptr
is deprecated and it cannot be used in Standard Library containers because it has a non intutive assignment behavior. unique_ptr
is the superior choice to auto_ptr
proposed by the new c++11 standard.
Note that which smart pointer to use depends on the lifetime and the ownership semantics of the element, check out the link to know how to choose one for your usage.
Upvotes: 2
Reputation: 754545
It sounds like you want to have a single value which will have a lifetime equivalent of the containing vector<T>
. If so this is a good place to consider using std::shared_ptr<T>
which is a ref counted pointer type
typedef std::shared_ptr<MyClass> MyClassPtr;
...
vector<MyClassPtr> myVec;
myVec.push_back(new MyClass(...));
Upvotes: 0
Reputation: 131779
C++11 has emplace_back
which will perfectly forward whatever you give it to the elements constructor and construct it directly in-place:
#include <vector>
#include <iostream>
struct X{
X(int i, float f, bool b){
std::cout << "X(" << i << ", " << f << ", " << b << ")\n";
}
};
int main(){
std::vector<X> vx;
vx.emplace_back(42, 3.14f, true);
}
In C++03, you're out of luck and have to live with the copy ctor call (or rather, two - one in the parameter, one into the vector's internal array). If your class is desgined correctly, it should only be a minor efficiency inconvenience.
Upvotes: 3