An std::unique_ptr is a smart pointer that exclusively owns and manages an object (or an array of objects) through a pointer. The exclusive ownership of an object requires that the managing unique_ptr cannot be copied to avoid the shared possession of the object at any point. However, a unique_ptr can be moved to another unique_ptr:
auto up = std::make_unique<std::string>("A string");
auto cup = up; //!ERROR. Can not copy.
auto mup = std::move(up); //OK
A unique_ptr is made non-copiable via deleted copy constructor and copy assignment operator. The copy constructor and the copy assignment operator in a typical implementation of unique_ptr are implicitly deleted. In a typical implementation of unique_ptr, the definitions of move constructor and move assignment operator cause implicit deletion of the copy constructor and the copy assignment operator because they are not explicitly defined.
The non-copiability affects how a unique_ptr is passed to a function. Passing a unique_ptr to a function that takes a unique_ptr by reference is a no-brainer because there is no copy (or move) involved:
void bar(std::unique_ptr<std::string>& refP) {
// ...
}
//call bar()
auto up = std::make_unique<std::string>("A large string");
bar(up); //OK. Passed by reference
However, a unique_ptr has to be moved while passing it to a function that takes a unique_ptr by value. The move could be explicit for an lvalue argument or implicit for a temporary, as shown below:
void foo(std::unique_ptr<std::string> cp) {
//...
}
//call foo
auto up = std::make_unique<std::string>("A large string");
foo(up); //!ERROR. No copy allowed.
foo(std::move(up)); //OK. Explicit move
foo(std::make_unique<std::string>("A large string")); //OK. Implicit move
Consider a function, func, that takes a unique_ptr by value:
void func(std::unique_ptr<std::string> cp) {
//...
}
Below are some use cases of calling func; one of them fails to compile:
A.
void callerA(const char* str) {
//...
auto up = std::make_unique<std::string>(str);
func(up.release());
//...
}
B.
void callerB(std::string* rawP) {
//...
func(std::unique_ptr<std::string>(rawP));
//...
}
C.
void callerC(std::unique_ptr<std::string>& refP) {
//...
func(std::move(refP));
//...
}
D.
void callerD(const std::string& refS) {
//...
auto up = std::make_unique<std::string>(refS);
//...
func(std::move(up));
//...
}
Select below the scenario from above that has an invalid call to func (fails to compile). Check Explanations
for details: