为何std::unique_ptr作为右值引用传递后,基类实例仍有效?
为什么
std::unique_ptr<Derived>调用foo后失效,而std::unique_ptr<Base>仍保持有效? 问题代码
#include <memory> #include <iostream> struct Base { }; struct Derived : public Base { }; void foo(std::unique_ptr<Base>&& b) { } int main() { std::unique_ptr<Derived> derived = std::make_unique<Derived>(); foo(std::move(derived)); std::cout << "derived after foo(): " << (derived? "valid\n" : "invalid\n"); std::unique_ptr<Base> base = std::make_unique<Derived>(); foo(std::move(base)); std::cout << "base after foo(): " << (base? "valid\n" : "invalid\n"); return 0; }
程序输出
derived after foo(): invalid base after foo(): valid
原因解释
核心差异在于调用foo时是否触发了std::unique_ptr的所有权转移(移动构造):
std::unique_ptr<Derived>的情况:std::unique_ptr<Derived>和函数参数std::unique_ptr<Base>&&是不同的模板实例类型,C++无法直接将前者的右值绑定到后者的引用上。此时会自动生成一个临时的std::unique_ptr<Base>对象,这个临时对象通过unique_ptr<Derived>的移动构造函数创建——这一步会把derived持有的指针所有权完全转移到临时对象中,导致derived被置空(变为无效)。临时对象随后绑定到函数参数b,函数结束后临时对象销毁,但derived已经失去所有权,因此输出invalid。std::unique_ptr<Base>的情况:std::move(base)的类型就是std::unique_ptr<Base>&&,和函数参数类型完全匹配。此时函数参数b只是绑定到base的右值引用上,并没有触发unique_ptr的移动构造或赋值操作——所有权没有发生任何转移。函数内部未对b做任何操作,因此base仍然持有原指针,保持有效状态,输出valid。
如果想让base也在调用foo后失效,可以在foo内部显式转移所有权,比如:
void foo(std::unique_ptr<Base>&& b) { auto temp = std::move(b); // 此时b(即原base)的所有权被转移到temp }
这样base就会被置空,输出invalid。
内容的提问来源于stack exchange,提问作者Kornel Szymkiewicz
相关产品推荐
相关产品推荐

