The std::unique_ptr has unique ownership of the object it manages. That means that more than one std::unique_ptr object can not contain the managed object pointer. That’s why we can not assign a std::unique_ptr to another one. For the same reason, we can not pass std::unique_ptr as an argument of a function.
But we can always move the ownership of the object to a new std::unique_ptr. After the move the assigned unique_ptr will own the managed object pointer. We’ll no longer be able to access the object from the old (source) unique_ptr.
class C {
public:
C() {
std::cout << "Constructing the class..." << std::endl;
}
~C() {
std::cout << "Destructing the class..." << std::endl;
}
void f() {
std::cout << "Printing from function f()..." << std::endl;
}
};
We can create a std::unique_ptr of type C. C is the class we defined here.
std::unique_ptr<C> pc = std::unique_ptr<C>(new C());
But we can not assign this unique_ptr, pc, to another unique_ptr.
std::unique_ptr<C> new_pc = pc;
This will produce a compilation error. But we can move the ownership of the actual pointer to new std::unique_ptr.
std::unique_ptr<C> new_pc = std::move(pc);
After this, pc will no longer own the actual pointer. We won’t be able to use the old unique_ptr, pc.
if(pc == nullptr) {
std::cout << "pc does not own the actual pointer" << std::endl;
}
The pc == nullptr check will return true. But we’ll be able to use the new sunique_ptr, new_pc, and call the new_pc->f() function.
Passing std::unique_ptr to a Function
Similar thing happens if we try to pass a std::unique_ptr as a function parameter.
std::unique_ptr<C> func1(std::unique_ptr<C> ptr)
{
ptr->f();
return ptr;
}
The func1() takes a unique_ptr of type C.
std::unique_ptr<C> pc = std::unique_ptr<C>(new C());
func1(pc)
This will produce compilation errors. But we can move the pc to the function parameter.
std::unique_ptr ret = func1(std::move(pc));
After this, pc will no longer own the actual pointer.
But when a function returns a std::unique_ptr, the ownership is automatically transferred to the returned variable. In this example, after func1 returns, ret will own the actual pointer. We’ll be able to call ret->f() function.