Firstly, what exactly is the difference between make_unique and plain old unique_ptr? Why do I need to include a separate template to use the former?
A related issue I faced today. Say I want to create a std::vector of objects. From what I understand, I have three options.
1) Use raw pointers, but be sure to cleanup using delete.
2) Use shared_ptr, which will ensure that your object is safely deleted once no one is referencing it.
3) Create a stack allocated object, then push that onto the vector. The vector will create a shallow copy of the object, and the original copy will be deleted at the end of the current scope.
In this scenario, I wouldn't be able to use unique_ptr, because that would mean that both the vector and the local scope have pointers to that object. Am I correct?
Are there other options for achieving this that I don't know of? Also, which one is the best approach for the general case? I ended up using shared_ptr and it seems to be working fine... I think.
> Firstly, what exactly is the difference between make_unique and plain old unique_ptr?
The make_unique function uses variadic templates to take the arguments to your constructor:
auto oldway = std::unique_ptr<Foo>(new Foo(1, 2));
auto newway = std::make_unique<Foo>(1, 2);
The new way has the small virtue of eliminating one more place where you ever need to call new. However, it also offers the library writer more possibilities in the internal implementation. For instance, they can nest your type in another struct for accounting purposes without copying or additional dereferencing. However the second advantage is more relevant to shared_ptr, which is probably why C++11 had make_shared, but not make_unique (added in C++14).
> I wouldn't be able to use unique_ptr, because that would mean that both the vector and the local scope have pointers to that object.
Yeah, if you're using unique_ptr, the pointer is uniquely owned in at most one place at a time. For your situation, I think the vector should probably own the objects, and you borrow them with references, iterators, or pointers (via the get() method). Be wary of holding on to those references though (the Rust fans will be quick to point out the dangers here).
A fourth option, which you should consider unless your objects are expensive to copy, is to make your objects copyable and not use unique_ptr or shared_ptr at all. I think it's much simpler to reason about objects as values than it is to reason about objects as smart pointers or (dumb) references.
> I ended up using shared_ptr and it seems to be working fine... I think.
Go with what works for you, but shared_ptr makes additional promises about thread safety and interactions with weak_ptr that increase its runtime costs. I wish shared_ptr was simple by default and that there was yet another smart pointer type for when you need those additional features.
The biggest reason to use make_unique and make_shared is to avoid the ancient C++ problem with non-deterministic order of evaluation. In code like this:
the only guarantee is that `new foo` and `new bar` will occur before the corresponding shared_ptr constructor, and all of them will occur before the call to foo. This means that the following is a valid sequence:
1. new foo
2. new bar
3. unique_ptr
...
Now, if constructor of bar throws, you've leaked foo.
With make_unique, construction and smart pointer acquisition is a single atomic operation - if it throws, everything gets cleaned up.
I think technically you could use unique_ptr and transfer ownership (move) when pushing into the vector, but the underlying "bad pattern" here is that you almost never want to have a vector of (smart) pointers. The vector should own the objects directly.
> Say I want to create a std::vector of objects. From what I understand, I have three options.
Vectors already own their contents, so there is no need to use unique_ptr here. The objects will be allocated on the heap either way, and you don't need a stack object either. Just push or emplace the object into your vector and be done with it. When the vector is deleted, so will its contents, automatically.
> The objects will be allocated on the heap either way, and you don't need a stack object either. Just push or emplace the object into your vector and be done with it. When the vector is deleted, so will its contents, automatically
I guess what you mean to say is that emplace_back will do the allocation and lifetime management. But using push_back on a stack-allocated object is going to result in a copy.
emplacement doesn't handle lifetime management; the vector itself does this, whether you emplace or push.
push_back with a stack object will copy the object, yes. Emplace_back with a stack object will also, they are not much different. But if you emplace by creating the object inside the emplace call itself, then there is no copy.
Firstly, what exactly is the difference between make_unique and plain old unique_ptr? Why do I need to include a separate template to use the former?
A related issue I faced today. Say I want to create a std::vector of objects. From what I understand, I have three options.
1) Use raw pointers, but be sure to cleanup using delete.
2) Use shared_ptr, which will ensure that your object is safely deleted once no one is referencing it.
3) Create a stack allocated object, then push that onto the vector. The vector will create a shallow copy of the object, and the original copy will be deleted at the end of the current scope.
In this scenario, I wouldn't be able to use unique_ptr, because that would mean that both the vector and the local scope have pointers to that object. Am I correct?
Are there other options for achieving this that I don't know of? Also, which one is the best approach for the general case? I ended up using shared_ptr and it seems to be working fine... I think.