理解C++中std::move与std::unique_ptr的所有权转移差异
关于
std::move与std::unique_ptr所有权转移的差异分析 先整理你给出的完整可运行代码:
#include <iostream> #include <memory> #include <string> class Dog { public: std::string name; Dog(std::string n) : name(n) {} }; void F1(std::unique_ptr<Dog>&& uPtr) { std::cout << "F1 \n"; } void test1() { std::unique_ptr<Dog> pD(new Dog("Gunner")); F1(std::move(pD)); if (pD == nullptr) { std::cout << "Null\n"; } std::cout << "Test \n"; } void F2(std::unique_ptr<Dog> uPtr) { std::cout << "F2 \n"; } void test2() { std::unique_ptr<Dog> pD(new Dog("Smokey")); F2(std::move(pD)); if (pD == nullptr) { std::cout << "Null\n"; } std::cout << "Test \n"; }
为什么test1中pD不会变空?
核心逻辑:std::move本身不做任何所有权转移,它只是把左值转换成右值引用类型,相当于给原对象贴了个"允许被移动"的标签。
在test1的流程里:
std::move(pD)只是将pD这个左值,转换成std::unique_ptr<Dog>&&类型的右值,但这个转换操作不会修改pD本身的状态,它依然持有原来的Dog对象指针。- F1的参数是右值引用
uPtr,这仅仅是pD的一个别名——F1内部没有对uPtr执行任何移动操作(比如用它初始化另一个unique_ptr,或者进行赋值),所以pD的所有权完全没被转移,自然不会变成nullptr。
如果要让test1里的pD变空,你需要在F1中手动触发所有权转移:
void F1(std::unique_ptr<Dog>&& uPtr) { std::cout << "F1 \n"; std::unique_ptr<Dog> localPtr = std::move(uPtr); // 这里才会转移所有权,原pD会被置为空 }
为什么test2中pD会变空?
因为F2的参数是传值的std::unique_ptr<Dog> uPtr,调用F2时会触发unique_ptr的移动构造函数:
std::move(pD)生成的右值,会被用来构造形参uPtr。而unique_ptr是独占所有权的智能指针,不允许拷贝,只能通过移动转移所有权——移动构造函数会把源对象(pD)的指针所有权转移到新对象(uPtr),同时强制把源对象置为nullptr。- 这一步是
unique_ptr的核心特性,所以调用完F2后,pD的所有权已经被转移,自然变成空指针。
内容的提问来源于stack exchange,提问作者sam
相关产品推荐
相关产品推荐

