Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

vector<unique_ptr> resizing with push_back - how does it work?

As far as I understand, when stuff is pushed_back into a vector, sometimes it has to allocate a new memory block, resulting in copying all the elements into it from the old memory block, calling their destructors. Since unique_ptr destructors delete the owned memory, how is it possible that they work with vector? Is it safe to use unique_ptr in vectors? Is it slower than regular pointers?

like image 465
Vittorio Romeo Avatar asked Apr 22 '13 06:04

Vittorio Romeo


2 Answers

According to cppreference, one of the use cases for std::unique_ptr is use in "move-aware containers", such as std::vector. This implies that std::vector<T> is smart enough to detect when T is movable, which is the case for std::unique_ptr, and use the move constructor when resizing the vector.

like image 115
user4815162342 Avatar answered Nov 15 '22 20:11

user4815162342


resulting in copying all the elements into it from the old memory block, calling their destructors. Since unique_ptr destructors delete the owned memory, how is it possible that they work with vector?

In fact, it's not strictly copying the elements any more, it is moving. For types that have no implicit or explicit move constructor, that's the same. But for unique_ptrs that means, new unique_ptrs are constructed in the newly allocated memory, given an rvalue-reference to the "old" unique_ptrs. Their move constructor does the right thing, i.e. it transfers ownership from the old to the new unique_ptrs, leaving the old ones empty so nothing gets deleted when they are destroyed.

Is it safe to use unique_ptr in vectors?

It's save to use unique_ptrs everywhere, as long as you respect language rules and "C++ common sense". That means, you will have to explicitly do stupid things to break unique_ptrs safe behavior. Among those are e.g. pretending to give ownership of the owned object to yet another smart pointer:

unique_ptr<T> ptr1 {new T()};
unique_ptr<T> ptr2 {ptr1.get()}; //two unique_ptr's owning the same object...

or some destructive actions involving reinterpret_cast, memcpy, memset or other stuff that don't respect C++ object lifetimes.

Is it slower than regular pointers?

Maybe. There is clearly some small overhead involved when moving a unique_ptr in comparison to copying a raw pointer, namely setting the original to zero. But whether that overhead can be optimized away or not depends on your compiler and optimizer. And as ever with performance, consult your profiler to assess whether it is slower and whether the slowdown matters. I bet it won't, and taking into account the amount of security the smart pointers will give you, just never ask about unique_ptr's performance.

Sidenote: If you know the size of your vector in advance, remeber to use vector::reserve(). It will save you the reallocations and moves of the unique_ptrs. And if you know only the approximate size your vector will have, don't be petty - unique_ptrs are not very big (normally as big as a raw pointer plus the deleter, which might or might not be optimized away), so reserving a few percent more won't hurt unless you really have tight memory constraints.

like image 22
Arne Mertz Avatar answered Nov 15 '22 20:11

Arne Mertz