Using std::unique_ptr with standard containers - c++

I've been looking for a way to do safe vectors and maps of dynamic pointers, when I realized C++11 adds unique_ptrs. I looked into how to use them on Google, but have been unsuccessful in looking for details. What I need to know are the following:
What, exactly, is different between pointers and unique_ptrs besides automatic memory collection?
How would I go about removing a unique_ptr from a vector or map? Is there any special code I have to use besides erasing the iterator?

Nothing. A unique_ptr is just a wrapper around a pointer, which deletes the pointer when the unique_ptr is destroyed. It has no overhead (just like the auto_ptr template it replaces).
Nope -- it will just work. The difficulty actually comes from inserting the pointer into the vector or map -- whereas you must move the unique_ptr into the container.

The difference is that unique_ptr obeys move semantics. Further, as the name suggests, you can't make copies of it.
Erasing an element of std::vector<std::unique_ptr<T> > will effectively delete whatever that pointer pointed at.

Related

Matrix of unique_ptr

Is it considered good practice to put unique_ptr in an array? Yes, I know, they have unusual copy semantic, but my idea is this:
I have a tiled-based game field. Each pointer in the array points to some game object. When I assign something new to an array element, the previous object is destroyed and a new one is placed.
Another question -- the same about shared_ptr, because sometimes I will use flyweight pattern.
One of unique_ptr's biggest advantages is that it's safe to use in Standard containers like std::vector. std::vector<std::unique_ptr<T>> is no anti-pattern, it's perfectly fine and highly recommended.
In general yes, this is good practice: in that case, the matrix would be the owner of the objects (which should work well in most cases) and other consumers of the object merely retain raw pointers to the objects, if at all.
This is safe and efficient.
On the other hand, consider whether you need pointers at all. If I understand correctly, the only reason for using pointers here is to be able to store polymorphic objects. Consider whether boost::variant may be an alternative here, or some kind of value_ptr (which unfortunately isn’t included in the standard library, but easy to implement).
There's nothing unusual about the copy semantics of unique_ptr; they can be moved but not copied, and hence are entirely suitable for use in a standard container.
You may be thinking of the deprecated auto_ptr which, before move semantics were added to the language, tried to emulate them using destructive copy semantics. This made them very difficult to safely use with standard containers.
Whether you should be storing pointers or objects in the container is another question. Generally, it's better to store objects; unless they're very large or otherwise expensive to move, or unless you need to store (pointers to the common base class of) objects of different types.
If you do want to store pointers, and want the container to manage the lifetime of the objects, then unique_ptr is the best choice. shared_ptr is also suitable, if you want to share ownership with other entities, or if you want to use weak_ptr to determine whether the object has been removed from the array.
In general unique_ptr is more performant than shared_ptr because it doesn't do reference counting, however one place must have ownership. This is risky because if you have:
vector<unique_ptr<GameObject>> v;
You would take a reference to it with:
GameObject* p = v[42].get();
and then if position 42 is deleted or replaced, p will be a hanging pointer.
However:
vector<shared_ptr<GameObject>> v;
shared_ptr<GameObject> p = v[42];
Will keep the underlying object around for p even if v[42] is deleted - but you have the overhead of the reference count update.
My suggestion would be to prefer shared_ptr because its safer, unless performance becomes an issue.

Trouble switching from vector of dumb pointers to boost::shared_ptr

Alright, this has had me stumped on and off for a couple of months now, so I'll see if anyone else can help with this.
So in my main program I have two kinds of structs (solarBody_t, ship_t) that are both derived from the same base class (physical_t). I make a vector of both objects, since I can't put a solarBody and a ship in the same vector. They are both dumb pointer vectors.
I tried putting both in the same vector, using a vector of boost::shared_ptrs. Now, to my understanding, shared_ptrs should have the same semantics and syntax as dumb pointers (e.g. foobar->mass = 42; should work for both). However, just changing the declaration to a vector of boost::shared_ptr to dumb pointers, it gives me an error when I try and push_back something to the vector of shared_ptrs.
From what I can tell, this should work. The boost docs give the example of
boost::shared_ptr<int> p(new int(2));
which is pretty much what I'm doing.
Has anyone had previous experiences with this? Or want to suggest another way to store everything in a vector?
For more details, here's the gist of it (kind of a contradiction of terms, but I made the pun, so there.)
I don't think it'll let you automatically construct a shared_ptr from a bare pointer. push_back is expecting a shared_ptr<foobar_t>, not a bare foobar_t. You should take a look at boost::make_shared and try something like this:
entity_smart.push_back(boost::make_shared<foobar_t>(42));
make_shared has a few advantages: namely, it allocates the pointer control block and the object itself in one allocation and keeps an unmatched new out of your code. It also makes it explicitly clear that you're creating a shared_ptr to an object.
Other than that, yes, the semantics should be basically the same. Keep in mind that shared_ptr may be overkill for what you're doing, though, if you don't actually need to share ownership of the objects.
Lateral thinking:
You do not actually need a shared_ptr here, what you want is a STL(-like) collection in which to store polymorphic values; the collection being the owner.
You have basically two solutions:
use a pointer-aware collection: boost::ptr_vector, from the Pointer Container library.
use a better pointer: std::unique_ptr, from the C++11 Standard
I would still advise boost::ptr_vector even if you have access to C++11 because it provides additional guarantees (null not allowed by default) and sugar coating (dereferencing an iterator gives a reference, not a pointer than you have to dereference once more).

storing pointers to auto_ptr in vector

Can one store pointers to auto_ptr(s) in a std::vector? Is it safe?
I enumerate a folder reading in XML files and creating an object for each with auto_ptr. I don't know in advance how many XML files there will be and I'd like to use a vector to essentially keep a list of pointers to them.
I'm also assuming that when a pointers are removed from the Vector (or the vector is destroyed) the pointers are pretty much gone, so I wouldn't have to worry about setting them to NULL.
You can't store an auto_ptr itself in a std::vector, but storing a plain pointer is fine, even if the thing it points to is an auto_ptr.
I don't see why you'd want to do that, though. The whole point of auto_ptr is to ensure that heap-allocated objects are deleted automatically when they go out of scope. You lose that benefit if the auto_ptr itself has to be deleted manually.
If you want to store heap-allocated objects safely in a vector, you can use std::tr1::shared_ptr instead of auto_ptr, or use Boost's pointer containers. Or, if you're using C++11, std::unique_ptr is like std::auto_ptr except it's safe to use in containers.
Yes you could - but it is totally unsafe and will do all sorts of unexpected things that will surprise you.
If you want to store smart pointers in a container have a look at unique_ptr if your compiler supports C++11 stuff

Pointer to vector vs vector of pointers vs pointer to vector of pointers

Just wondering what you think is the best practice regarding vectors in C++.
If I have a class containing a vector member variable.
When should this vector be declared a:
"Whole-object" vector member varaiable containing values, i.e. vector<MyClass> my_vector;
Pointer to a vector, i.e vector<MyClass>* my_vector;
Vector of pointers, i.e. vector<MyClass*> my_vector;
Pointer to vector of pointers, i.e. vector<MyClass*>* my_vector;
I have a specific example in one of my classes where I have currently declared a vector as case 4, i.e. vector<AnotherClass*>* my_vector;
where AnotherClass is another of the classes I have created.
Then, in the initialization list of my constructor, I create the vector using new:
MyClass::MyClass()
: my_vector(new vector<AnotherClass*>())
{}
In my destructor I do the following:
MyClass::~MyClass()
{
for (int i=my_vector->size(); i>0; i--)
{
delete my_vector->at(i-1);
}
delete my_vector;
}
The elements of the vectors are added in one of the methods of my class.
I cannot know how many objects will be added to my vector in advance. That is decided when the code executes, based on parsing an xml-file.
Is this good practice? Or should the vector instead be declared as one of the other cases 1, 2 or 3 ?
When to use which case?
I know the elements of a vector should be pointers if they are subclasses of another class (polymorphism). But should pointers be used in any other cases ?
Thank you very much!!
Usually solution 1 is what you want since it’s the simplest in C++: you don’t have to take care of managing the memory, C++ does all that for you (for example you wouldn’t need to provide any destructor then).
There are specific cases where this doesn’t work (most notably when working with polymorphous objects) but in general this is the only good way.
Even when working with polymorphous objects or when you need heap allocated objects (for whatever reason) raw pointers are almost never a good idea. Instead, use a smart pointer or container of smart pointers. Modern C++ compilers provide shared_ptr from the upcoming C++ standard. If you’re using a compiler that doesn’t yet have that, you can use the implementation from Boost.
Definitely the first!
You use vector for its automatic memory management. Using a raw pointer to a vector means you don't get automatic memory management anymore, which does not make sense.
As for the value type: all containers basically assume value-like semantics. Again, you'd have to do memory management when using pointers, and it's vector's purpose to do that for you. This is also described in item 79 from the book C++ Coding Standards. If you need to use shared ownership or "weak" links, use the appropriate smart pointer instead.
Deleting all elements in a vector manually is an anti-pattern and violates the RAII idiom in C++. So if you have to store pointers to objects in a vector, better use a 'smart pointer' (for example boost::shared_ptr) to facilitate resource destructions. boost::shared_ptr for example calls delete automatically when the last reference to an object is destroyed.
There is also no need to allocate MyClass::my_vector using new. A simple solution would be:
class MyClass {
std::vector<whatever> m_vector;
};
Assuming whatever is a smart pointer type, there is no extra work to be done. That's it, all resources are automatically destroyed when the lifetime of a MyClass instance ends.
In many cases you can even use a plain std::vector<MyClass> - that's when the objects in the vector are safe to copy.
In your example, the vector is created when the object is created, and it is destroyed when the object is destroyed. This is exactly the behavior you get when making the vector a normal member of the class.
Also, in your current approach, you will run into problems when making copies of your object. By default, a pointer would result in a flat copy, meaning all copies of the object would share the same vector. This is the reason why, if you manually manage resources, you usually need The Big Three.
A vector of pointers is useful in cases of polymorphic objects, but there are alternatives you should consider:
If the vector owns the objects (that means their lifetime is bounded by that of the vector), you could use a boost::ptr_vector.
If the objects are not owned by the vector, you could either use a vector of boost::shared_ptr, or a vector of boost::ref.
A pointer to a vector is very rarely useful - a vector is cheap to construct and destruct.
For elements in the vector, there's no correct answer. How often does the vector change? How much does it cost to copy-construct the elements in the vector? Do other containers have references or pointers to the vector elements?
As a rule of thumb, I'd go with no pointers until you see or measure that the copying of your classes is expensive. And of course the case you mentioned, where you store various subclasses of a base class in the vector, will require pointers.
A reference counting smart pointer like boost::shared_ptr will likely be the best choice if your design would otherwise require you to use pointers as vector elements.
Complex answer : it depends.
if your vector is shared or has a lifecycle different from the class which embeds it, it might be better to keep it as a pointer.
If the objects you're referencing have no (or have expensive) copy constructors , then it's better to keep a vector of pointer. In the contrary, if your objects use shallow copy, using vector of objects prevent you from leaking...

Memory management with new keyword and an STL vector of pointers

How is the destructor for the vector managed when adding elements to this list? Is the object destroyed correctly when it goes out of scope? Are there cases where it would not delete the object correctly? For example what are the consequences if "table" was a child of object, and we added a new table to a vector of object pointers?
vector <object*> _objectList;
_objectList.PushBack(new object);
Since you're making a vector of "bare" pointers, C++ can't possibly know that the pointers in question are meant to have "ownership" of the objects they point to, and so it will not call those objects' destructors when the pointer goes away. You should use a simple "smart" pointer instead of a "bare" pointer as the vector's item. For example, Boost's shared_ptr would be perfectly adequate for the task (although you can surely do it with "cheaper", lighter-weight approaches, if you don't want to deal with Boost as a whole and have no other need for smart pointers in your code).
Edit: since you (the OP) say that using a framework such as Boost is not feasible, and a couple comments usefully point out that even wrapping std::auto_ptr doesn't really qualify as a decent shortcut, you may have to implement your own smart pointers (or, if you find an open-source, stand-alone smart pointer template class that looks usable, audit it for compliance with your requirements). This article is a useful primer to smart pointers in C++, whether you have to roll your own or audit an existing implementation.
You could use bost 'ptr_vector'. It will automatically destruct objects that the items point to when they are either deleted or the instance of ptr_vector goes out of scope. More info is available here.
In your case, the object pointers are destroyed properly, but the actual objects themselves won't be touched. The STL properly destructs all contained elements - but will not implicitly dereference pointers to types.
STL Vectors make a copy of whatever you put in there, and ultimately delete that copy.
So in this case, the vector is storing a pointer to an object - not the object itself. So it makes a copy of the pointer, and deletes the pointer. But, as Chris said, the object itself will not be deleted.
So, solutions:
If you don't really need to use pointers, then don't:
vector <object> _objectList;
_objectList.PushBack(object());
If you do need to use pointers, you can either use a smart pointer (which handles reference counting for you, and will delete the object along with the pointer), as Alex suggested, or use a ptr_vector, as Igor mentioned.