Is there any use for unique_ptr with array?
Solution 1:
Some people do not have the luxury of using std::vector
, even with allocators. Some people need a dynamically sized array, so std::array
is out. And some people get their arrays from other code that is known to return an array; and that code isn't going to be rewritten to return a vector
or something.
By allowing unique_ptr<T[]>
, you service those needs.
In short, you use unique_ptr<T[]>
when you need to. When the alternatives simply aren't going to work for you. It's a tool of last resort.
Solution 2:
There are tradeoffs, and you pick the solution which matches what you want. Off the top of my head:
Initial size
-
vector
andunique_ptr<T[]>
allow the size to be specified at run-time -
array
only allows the size to be specified at compile time
Resizing
-
array
andunique_ptr<T[]>
do not allow resizing -
vector
does
Storage
-
vector
andunique_ptr<T[]>
store the data outside the object (typically on the heap) -
array
stores the data directly in the object
Copying
-
array
andvector
allow copying -
unique_ptr<T[]>
does not allow copying
Swap/move
-
vector
andunique_ptr<T[]>
have O(1) timeswap
and move operations -
array
has O(n) timeswap
and move operations, where n is the number of elements in the array
Pointer/reference/iterator invalidation
-
array
ensures pointers, references and iterators will never be invalidated while the object is live, even onswap()
-
unique_ptr<T[]>
has no iterators; pointers and references are only invalidated byswap()
while the object is live. (After swapping, pointers point into to the array that you swapped with, so they're still "valid" in that sense.) -
vector
may invalidate pointers, references and iterators on any reallocation (and provides some guarantees that reallocation can only happen on certain operations).
Compatibility with concepts and algorithms
-
array
andvector
are both Containers -
unique_ptr<T[]>
is not a Container
I do have to admit, this looks like an opportunity for some refactoring with policy-based design.
Solution 3:
One reason you might use a unique_ptr
is if you don't want to pay the runtime cost of value-initializing the array.
std::vector<char> vec(1000000); // allocates AND value-initializes 1000000 chars
std::unique_ptr<char[]> p(new char[1000000]); // allocates storage for 1000000 chars
The std::vector
constructor and std::vector::resize()
will value-initialize T
- but new
will not do that if T
is a POD.
See Value-Initialized Objects in C++11 and std::vector constructor
Note that vector::reserve
is not an alternative here: Is accessing the raw pointer after std::vector::reserve safe?
It's the same reason a C programmer might choose malloc
over calloc
.
Solution 4:
An std::vector
can be copied around, while unique_ptr<int[]>
allows expressing unique ownership of the array. std::array
, on the other hand, requires the size to be determined at compile-time, which may be impossible in some situations.