You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 18:42:37