If you don\'t need dynamic growth and don\'t know the size of the buffer at compile time, when should unique_ptr
be used instead of vector<
std::vector
stores the length of both the size of the variable and the size of the allocated data along with the pointer to the data it's self. std::unique_ptr
just stores the pointer so there may be a small gain in using std::unique_ptr
.
No one has yet mentioned the vector provides iterators and function such and size()
where as unique ptr does not. So if iterators are needed use std::vector
Objective Part:
No, there probably shouldn't be a significant performance difference between the two (though I suppose it depends on the implementation and you should measure if it's critical).
Subjective Part:
std::vector
is going to give you a well known interface with .size()
and .at()
and iterators, which will play nicely with all sorts of other code. Using std::unique_ptr
gives you a more primitive interface and makes you keep track of details (like the size) separately. Therefore, barring other constraints, I would prefer std::vector
.
There is no performance loss in using std::vector
vs. std::unique_ptr<int[]>
. The alternatives are not exactly equivalent though, since the vector could be grown and the pointer cannot (this can be and advantage or a disadvantage, did the vector grow by mistake?)
There are other differences, like the fact that the values will be initialized in the std::vector
, but they won't be if you new
the array (unless you use value-initialization...).
At the end of the day, I personally would opt for std::vector<>
, but I still code in C++03 without std::unique_ptr
.
If you're in a position where vector<int>
is even a possibility, you probably want to go with that except in extreme and rare circumstances. And even then, a custom type instead of unique_ptr<int[]>
may well be the best answer.
So what the heck is unique_ptr<int[]>
good for? :-)
unique_ptr<T[]>
really shines in two circumstances:
1.
You need to handle a malloc/free resource from some legacy function and you would like to do it in a modern exception safe style:
void
foo()
{
std::unique_ptr<char[], void(*)(void*)> p(strdup("some text"), std::free);
for (unsigned i = 0; p[i]; ++i)
std::cout << p[i];
std::cout << '\n';
}
2.
You've need to temporarily secure a new[] resource before transferring it onto another owner:
class X
{
int* data_;
std::string name_;
static void validate(const std::string& nm);
public:
~X() {delete [] data_;}
X(int* data, const std::string& name_of_data)
: data_(nullptr),
name_()
{
std::unique_ptr<int[]> hold(data); // noexcept
name_ = name_of_data; // might throw
validate(name_); // might throw
data_ = hold.release(); // noexcept
}
};
In the above scenario, X
owns the pointer passed to it, whether or not the constructor succeeds. This particular example assumes a noexcept
default constructor for std::string
which is not mandated. However:
std::string
.std::string
default constructor that throws is lame.C++14 introduces std::dynarray for that purpose.
Now, between these two constructions :
auto buffer = std::make_unique<int[]>( someCount );
auto buffer = std::vector<int>( someCount, someValue );
The first gives you an uninitialized array of int but the second initializes it with a value ( 0 if not provide ). So if you do not need the memory to be initialized because you will overwrite it somehow later with something more complex than std::fill
, choose 1, if not, choose 2.