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

为何可多次移动unique_ptr变量?&&形参与普通形参有何区别?

问题解答

一、为什么能多次用std::move(val)调用print函数?

核心原因有两个:

  1. std::move只是类型转换,不做实际移动:它的作用仅仅是把左值(比如你的val)转换成对应类型的右值引用,不会修改原对象的状态,也不会转移unique_ptr的所有权。
  2. 你的print函数没触发所有权转移:print的形参是std::unique_ptr<int> &&v,这是右值引用,它只是绑定到std::move(val)生成的右值引用上,函数里只是解引用v读值,没有把v赋值给其他unique_ptr,也没调用移动构造/赋值函数。

所以两次调用print时,val的所有权一直没丢,它始终握着指向int(1)的指针,自然能被多次转成右值引用传进去。要是把print的形参改成std::unique_ptr<int> v(值传递),第一次调用就会触发移动构造,val的所有权会被转移到形参v里,val变成空指针,第二次再传就会因为解引用空指针触发未定义行为。

二、带&&的形参与不带&&的形参区别

分两种常见的不带&&的情况对比:

1. 值传递形参(比如std::unique_ptr<int> v)

  • 调用函数时,会用实参新建一个形参对象:如果实参是右值(比如std::move(val)),走移动构造;如果是左值,走复制构造(但unique_ptr禁用了复制,所以直接传左值会编译报错)。
  • 形参是独立对象,函数结束后会被销毁,原实参的状态会跟着变(比如移动构造后,原unique_ptr会变成空)。

2. 左值引用形参(比如std::unique_ptr<int> &v)

  • 形参就是原实参的别名,直接绑定左值实参,不会新建对象。
  • 函数里改形参会直接影响原实参,但没法绑定右值(比如std::move(val)是右值,传不进去)。

3. 右值引用形参(比如std::unique_ptr<int> &&v)

  • 形参绑定到右值实参(包括std::move转的左值、临时对象等),是原对象的引用,不会新建对象。
  • 函数里可以修改原对象状态(比如在print里写auto tmp = std::move(v);,就会转移val的所有权),但如果只是读值,原对象状态不变。
  • 主要用来区分左值/右值实参,实现完美转发或者精准控制移动语义。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 19:13:14