It seems like std::unique_ptr
solves a problem that can also be solved with move-semantics, ie transferring ownership of a uniquely-owned resource. Here are some examples where they seem to perform the same job:
class SomeResource { /* resourcey stuff */ };
void ProcessResourcePtr(std::unique_ptr<SomeResource> r) { /* do stuff */ }
void ProcessResourceRvalRef(SomeResource&& r) { /* do stuff */ }
class OwnerOfResourcePtr {
private:
std::unique_ptr<SomeResource> r_;
public:
OwnerOfResourcePtr(std::unique_ptr<SomeResource> r) : r_(std::move(r)) { }
};
class OwnerOfResourceRvalRef {
private:
SomeResource r_;
public:
OwnerOfResourceRvalRef(SomeResource&& r) : r_(std::move(r)) { }
};
int main()
{
// transfer ownership to function via unique_ptr
std::unique_ptr<SomeResource> r1(new SomeResource());
ProcessResourcePtr(std::move(r1));
// transfer ownership to function via rvalue ref
SomeResource r2;
ProcessResourceRvalRef(std::move(r2));
// transfer ownership to instance via unique_ptr
std::unique_ptr<SomeResource> r3(new SomeResource());
OwnerOfResourcePtr(std::move(r3));
// transfer ownership to instance via rvalue ref
SomeResource r4;
OwnerOfResourceRvalRef(std::move(r4));
return 0;
}
To my eye, these both solve almost exactly the same problem in slightly different ways. I'm not 100% clear on the advantages of one way versus the other. I know that pointer moves are probably faster than move constructors/assignments, although both are usually assumed to be quite efficient. I'm also aware that move semantics allow you to keep your data on the stack (see r2, r4) instead of requiring a heap allocation/deallocation with new/malloc/etc (see r1, r3), which I think is a good thing (is it?).
In general when should one prefer a unique_ptr
over move semantics, or vice-versa? Are there any use cases that can only be solved by one or the other?
If you have a class (perhaps written by someone else) which does not have a move constructor, perhaps not even a copy constructor, then you may have to use unique_ptr
.
If an instance is optional, ie may not be present, you should use unique_ptr
.
If you can only initialize an object after your constructor is called, and the object is not default-constructible, you must delay construction, and can use unique_ptr
for this.
Even if a class has a move constructor, that might be more expensive than moving a single pointer. For example, if the class contains dozens of POD instances, or an array.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.