I am having this problem that I often use a vector of pointers to some objects.
The problem is that I need to delete pointers in that vector manually which is prone to errors / memory leaks.
Currently I am doing it like this:
1 2 3 4 5 6 7 8 9 10
typedef std::vector<MyObject*> TMyObjects;
void deleteVectors(TMyObjects &MyObjects)
{
for (auto i = MyObjects.begin(); i != MyObjects.end(); ++i)
{
delete((*i));
}
MyObjects.clear();
}
So I would like to get rid of using deleteVectors. I've found two solutions to this problem:
1. I could use Boost library which has pointer containers created for this purpose.
2. I could create a custom allocator which I pass when creating the instance of vector.
I don't want to use the Boost library so I am left up with the solution number 2. The thing is, that my C++ knowledge is yet not good enough to write such allocator by myself. Could someone help me or point me to a code snippet that perfrom this task?
> how about the solution based on custom allocator?
A standard allocator-aware container would use its allocator for managing storage for the values it holds.
std::vector< MyObject*, my_custom_allocator > would use the allocator to manage storage for holding pointers to MyObject, not for the MyObject instances that these pointers point to.
To illustrate,
1 2 3 4 5 6 7 8 9
std::vector< MyObject*, my_custom_allocator > my_vector ;
my_vector.push_back(nullptr) ;
my_vector.push_back(nullptr) ;
static MyObject my_first_object( /* ... */ ) ;
my_vector[0] = std::addressof(my_first_object) ; // the allocator does not get to know about this
my_vector[1] = new MyObject( /* ... */ ) ; // the allocator does not get to know about this
> am I wrong thinking that my_custom_allocator is able to call the destructor for the dereferenced pointer?
It won't be able to do that (with a dumb pointer) consistently and correctly.
For instance, consider:
1 2 3 4 5 6 7 8 9 10
void foo( std::vector< MyObject*, my_custom_allocator > arg ) // passed by value
{
// ...
// arg is destroyed when the function returns; the destructor would ask the allocator to
// destroy the pointers and deallocate the memory
}
std::vector< MyObject*, my_custom_allocator > my_vector ;
my_vector.push_back( new MyObject( /* ... */ ) ;
foo( my_vector ) ; // pass a copy of my_vector
I think I understand now. So I've tried to use your suggestion with container of smart pointers but I am having problem when I try to pass object to the vector by initializer list.
#include "stdafx.h"
#include <memory>
#include <vector>
class TMyObject
{
public:
TMyObject(int ID) : id(ID) {};
int id;
TMyObject(TMyObject&& o) {};
TMyObject(const TMyObject&) = delete;
TMyObject& operator=(const TMyObject&) = delete;
};
typedef std::unique_ptr<TMyObject> uTMyObject;
typedef std::vector<uTMyObject> TMyObjects;
int main()
{
//Error C2280 'std::unique_ptr<TMyObject,std::default_delete<_Ty>>::unique_ptr(const std::unique_ptr<_Ty,std::default_delete<_Ty>> &)':
//attempting to reference a deleted function SmartPointers2015 c : \program files(x86)\microsoft visual studio 14.0\vc\include\xmemory0 737
TMyObjects lMyObjects({ uTMyObject(new TMyObject(1)) });
return 0;
}
Could you explain me the reason of the error and how to fix it?
Is this because initializer list is creating a temporary vector which then is passed to lMyObjects and it tries to copy elements of this vector which are unique pointers that can't be copied?
std::initializer_list<T> is a proxy for an array of objects.
The vector needs to copy the objects from the underlying array, and std::unique_ptr<> is not copyable (deleted copy constructor)
Something like this perhaps:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
class TMyObject
{
public:
TMyObject(int ID) : id(ID) {};
int id;
TMyObject(TMyObject&& o) {};
TMyObject(const TMyObject&) = delete;
TMyObject& operator=(const TMyObject&) = delete;
};
int main()
{
std::vector< std::unique_ptr<TMyObject> > my_objects ;
my_objects.push_back( std::make_unique<TMyObject>(1) ) ; // move constructed into the vector
my_objects.push_back( std::unique_ptr<TMyObject>( new TMyObject(2) ) ) ; // clumsy, avoid
// use std::make_unique instead
}