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

std::unique_ptr嵌套场景下std::move底层实现机制问询

std::move在unique_ptr嵌套场景下的执行逻辑解析

定义的结构体

struct Foo{
    int val = 0;
    std::unique_ptr<Foo> child_a = nullptr;
    std::unique_ptr<Foo> child_b = nullptr;
    Foo(int val_):val(val_){}
    ~Foo(){std::cout<<"Deleting foo "<<val<<std::endl;}
};

(注:将原代码中的NULL替换为C++更推荐的nullptr,语义完全一致)

构建树形结构的代码

std::unique_ptr<Foo> root = std::make_unique<Foo>(0);
root->child_a = std::make_unique<Foo>(1);
root->child_b = std::make_unique<Foo>(2);
root->child_a->child_a = std::make_unique<Foo>(3);
root->child_a->child_b = std::make_unique<Foo>(4);
root->child_b->child_a = std::make_unique<Foo>(5);
root->child_b->child_b = std::make_unique<Foo>(6);

(注:原代码中std::make_unique<Foo>(Foo(0))可简化为std::make_unique<Foo>(0),直接传递构造参数即可避免多余拷贝)

执行root = std::move(root->child_a)的具体过程

  1. 转换右值引用:std::move(root->child_a)仅将root->child_a这个unique_ptr转换成右值引用,这一步不会销毁任何对象,只是标记该指针允许被移动。
  2. 执行移动赋值:
    • root的移动赋值运算符会接管右值引用指向的对象(即val=1的Foo节点),此时root的所有权转移到val=1的节点及其子节点(val=3、4)上。
    • 紧接着,root原本持有的val=0的Foo对象会被释放:
      • 调用val=0对象的析构函数,析构时会依次处理它的成员child_a和child_b:
        • 由于child_a已经被移动,内部指针被置为空,销毁这个unique_ptr时无任何操作;
        • child_b仍指向val=2的节点,因此触发val=2节点的析构,进而递归销毁val=2的child_a(val=5)和child_b(val=6)。
  3. 最终结果:val=1、3、4的节点被root保留,val=0、2、5、6的节点被销毁,输出对应的日志信息。

权威学习资源

  • 《C++ Primer》(第5版):第12章“动态内存”、第13章“拷贝控制”详细讲解了unique_ptr的所有权语义、移动操作的核心逻辑。
  • 《Effective Modern C++》:条款23“理解std::move和std::forward”、条款18“使用std::unique_ptr管理独占资源”,深入剖析了移动语义的本质和智能指针的正确用法。
  • C标准文档(C11及后续版本):关于std::unique_ptr移动赋值运算符的规范,明确了移动操作会转移所有权并置空原指针的行为。

内容的提问来源于stack exchange,提问作者user3353819

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.23 15:18:04