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

理解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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 18:40:19