Is it safe? To a point.
Naming
I hope the name Pointer
is just for illustration purposes as otherwise that is a pretty terrible name.
The changes I would make are:
Accepting pointers must indicate ownership.
Your current interface does not indicate that it is taking ownership of the pointers. So as a user of your class I need to dig inside and find out if you are taking ownership or not before I can use it.
void push_back(Pointer * pointer);
I would change the interface to specifically take a unique_ptr that way people know that you are taking ownership of the object.
void push_back(std::unqiue_ptr<Pointer> pointer);
No confusion here.
Storage of pointers.
I have no problem with you storing a vector of pointers or a vector of smart pointer. Either makes sense. As long as you define the Copy Constructor/ Assignment Operator and Destrtuctor if you use pointer (like you have). You could argue that keeping an array of smart pointers will save you some work in coding (tiny (probably insignificant cost1 of managing the data). Alternatively you can use a container specifically designed to hold pointers.
std::vector<Pointer*> data; // Add Rule of Three.
std::vector<std::unique_ptr<Pointer>> data; //
boost::ptr_vector<Pointer> data; // Takes ownership of pointers.
// Only exposes members as references
// to actual object (not pointer) and thus
// makes using it with standard algorithms
// much easier and intuitive.
To Clarify because of comments: I suspect for most compilers the cost of std::unique_ptr will be zero at runtime. But it is something worth validating with your compiler before assuming.
Access from derived types.
Personally I would not give direct access to the vector from derived class like that.
protected:
std::vector<Pointer *> pointers;
Even if you have a vector of unique_ptr it is still to easy for the derived class to break encapsulation and do something you don't intend. You should provide them with a safer interface. How you do that depends.
If you know none of the members will be NULL then I would provide them with a function that returns a reference.
protected:
// Anybody that wants to access the data gets a reference.
Pointer& data(std::size_t index) {return *pointers[index];}
// Note: the above code just uses the original code as a base line.
// If you change the storage medium I would probably still
// provide this as an interface layer so that I don't
// break encapsulation.
//
// Of course there are a lot of caviats that depend on how
// this will be used. But without further context this is
// the best I can do at the moment.
private:
std::vector<Pointer*> pointers;
If you want derived classes to modify the class you may need to think of something else. But you have not provided enough context for me to go further.
Iterator
Based on comments just showing how easy it would be to throw an iterator together that can be used without exposing implementations details. Note: this one is not complete but shows enough of how it would work (and I was slightly bored at the time and wanted to write some code).
class MyIterator
{
Keeper* parent;
int index
public:
MyIterator(Keeper& parent, int index)
: parent(&parent)
, index(index)
{}
MyIterator& operator++()
{
++index;
return *this;
}
MyIterator operator++(int)
{
MyIterator result(*this);
++(*this);
return result;
}
Pointer& operator*()
{
return parent->data(index);
}
}
shared_ptr
is obviously wrong. You could useunique_ptr
, butvector<Pointer>
would be much better. Btw. what is the purpose of the private pointers? \$\endgroup\$vector<Pointer>
orvector<Pointer *>
? \$\endgroup\$Pointer
a concrete type? Second, there appears to be no way to access the pointers once they're in theKeeper
. The only way I can see that could be useful is if the sole point to this class is to do something like garbage collection. \$\endgroup\$Pointer
is just a type (interface/abstract class) andKeeper
accepts classes that inherits fromPointer
. - Now I'm wondering... if my vector is private, does the inheriting class copy the vector? And isn't if safe that the vector is protected and the inheriting classes can access it as friend? If the inheriting class delete one of those pointers of the vector will result in a mess, right? \$\endgroup\$