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

C++中unique_ptr为何看似可复制、按值传递?

你的核心认知误区

你完全混淆了两个概念:拷贝unique_ptr智能指针对象本身,和拷贝unique_ptr指向的底层托管对象。所有资料里提到的禁止复制规则,约束的是前者,而你的所有测试代码做的都是后者,当然不会触发报错。


先明确unique_ptr的拷贝禁止规则到底限制了什么

std::unique_ptr的核心设计语义是独占托管对象的所有权,因此它的拷贝构造函数、拷贝赋值运算符是被显式删除的,以下行为才是明确被禁止的:

  • 用一个已存在的unique_ptr实例直接拷贝构造另一个unique_ptr实例
  • 将unique_ptr实例按值作为函数参数传递(传参过程会触发拷贝构造)
  • 将一个unique_ptr实例直接拷贝赋值给另一个已存在的同类型unique_ptr实例
  • 在C++标准库算法中,如果操作要求拷贝容器内存储的unique_ptr元素(比如对存储unique_ptr的容器调用需要复制元素的拷贝类算法),会直接编译失败

逐行解释你的测试代码为什么能正常运行

你代码里的所有操作,全是在操作解引用后拿到的底层int值,从来没有触发过unique_ptr自身的拷贝逻辑:

  • int num1 = *uniquePtr1;:*uniquePtr1返回的是unique_ptr托管的int类型左值引用,你只是把这个int的值拷贝给了普通变量num1,和拷贝智能指针本身没有任何关系。
  • int num2 = test(*uniquePtr1);:你传给test函数的是解引用后的int值,按值传递的是基础类型int,不是unique_ptr对象。如果你写test(uniquePtr1)才会触发编译错误——这才是按值传递unique_ptr的禁止写法。
  • *ptr1 = *uniquePtr1;:同样是把uniquePtr1指向的int值,拷贝到裸指针ptr1指向的独立内存中,全程没有操作unique_ptr对象本身。
  • *uniquePtr2 = *uniquePtr1;:这是最容易造成误解的一行。你在定义uniquePtr2时已经给它单独分配了一块新的int内存,这行代码做的是把uniquePtr1指向的int值,拷贝赋值到uniquePtr2指向的内存地址里。两个unique_ptr始终各自独占自己管理的内存,所有权没有发生任何转移或复制,根本不触发智能指针的拷贝赋值逻辑。如果你写uniquePtr2 = uniquePtr1;才是被禁止的操作——这行才是尝试把uniquePtr1本身拷贝赋值给uniquePtr2,会直接编译报错。

验证禁止规则的错误写法示例

你可以把以下代码加入你的测试文件,编译器会直接报「调用了被删除的函数」的错误,这才是资料里描述的被禁止的场景:

// 1. 尝试拷贝构造unique_ptr:编译失败
std::unique_ptr<int> uniquePtr3 = uniquePtr1;

// 2. 尝试按值传递unique_ptr:编译失败
// 先修改test函数签名为int test(std::unique_ptr<int> p),再调用test(uniquePtr1)
int test(std::unique_ptr<int> p) {
    return *p;
}

// 3. 尝试拷贝赋值unique_ptr:编译失败
uniquePtr2 = uniquePtr1;

另外提一句,你贴的测试代码有个笔误:你定义的裸指针变量名是ptr1,最后delete的却是ptr2,这会触发编译错误或者未定义行为,记得修正。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 01:24:20