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

Lambda中捕获std::move的std::unique_ptr编译失败原因咨询

Lambda捕获std::unique_ptr后使用std::move失败的原因解析

第一个示例:函数按值接收std::unique_ptr

代码

#include <memory>

void sink(std::unique_ptr<int> p) {
    // Do something with `p`
}

int main() {
    auto p = std::make_unique<int>(42);
    auto f = [p = std::move(p)](){
        sink(std::move(p));
    };
    f();
    return 0;
}

错误信息

<source>:10:13: error: use of deleted function 'std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = int; _Dp = std::default_delete<int>]'
   10 |         sink(std::move(p));
      |         ~~~~^~~~~~~~~~~~~~
In file included from /opt/compiler-explorer/gcc-14.2.0/include/c++/14.2.0/memory:78,
                 from <source>:1:
/opt/compiler-explorer/gcc-14.2.0/include/c++/14.2.0/bits/unique_ptr.h:516:7: note: declared here
  516 |       unique_ptr(const unique_ptr&) = delete;
      |       ^~~~~~~~~~
<source>:10:13: note: use '-fdiagnostics-all-candidates' to display considered candidates
   10 |         sink(std::move(p));
      |         ~~~~^~~~~~~~~~~~~~
<source>:3:32: note:   initializing argument 1 of 'void sink(std::unique_ptr<int>)'
    3 | void sink(std::unique_ptr<int> p) {
      |           ~~~~~~~~~~~~~~~~~~~~~^
Compiler returned: 1

原因解析

Lambda表达式的operator()默认是const成员函数,这意味着Lambda内部捕获的所有变量都被视为const类型。这里捕获的p在Lambda内部是const std::unique_ptr<int>,调用std::move(p)会生成一个const std::unique_ptr<int>&&类型的右值。

当尝试将这个const右值传递给sink(需要std::unique_ptr<int>)时,编译器会尝试调用std::unique_ptr的拷贝构造函数——因为const右值无法触发移动构造(移动构造需要非const的右值),而std::unique_ptr的拷贝构造函数是被显式删除的,因此编译报错。


第二个示例:函数按右值引用接收std::unique_ptr

代码

#include <memory>

void sink(std::unique_ptr<int> &&p) {
    // Do something with `p`
}

int main() {
    auto p = std::make_unique<int>(42);
    auto f = [p = std::move(p)](){
        sink(std::move(p));
    };
    f();
    return 0;
}

错误信息

<source>: In lambda function:
<source>:10:23: error: binding reference of type 'std::unique_ptr<int>&&' to 'std::remove_reference<const std::unique_ptr<int>&>::type' {aka 'const std::unique_ptr<int>'} discards qualifiers
   10 |         sink(std::move(p));
      |              ~~~~~~~~~^~~
<source>:3:34: note:   initializing argument 1 of 'void sink(std::unique_ptr<int>&&)'
    3 | void sink(std::unique_ptr<int> &&p) {
      |           ~~~~~~~~~~~~~~~~~~~~~~~^
Compiler returned: 1

原因解析

同样是因为Lambda的operator()默认是const成员函数,捕获的p在Lambda内部是const std::unique_ptr<int>。std::move(p)生成的是const std::unique_ptr<int>&&,而sink的参数是std::unique_ptr<int>&&(非const右值引用)。

C++中,非const的右值引用无法绑定到const右值——因为这会允许修改原本被const保护的对象,违反const语义。因此编译器报错,提示丢弃了const限定符。


解决方法

要解决这个问题,只需要在Lambda声明时添加mutable关键字,这样Lambda的operator()就不再是const成员函数,内部捕获的变量也会变成非const类型,std::move就能生成正确的非const右值:

#include <memory>

void sink(std::unique_ptr<int> p) {
    // Do something with `p`
}

int main() {
    auto p = std::make_unique<int>(42);
    // 添加mutable关键字
    auto f = [p = std::move(p)]() mutable {
        sink(std::move(p));
    };
    f();
    return 0;
}

第二个示例同样只需添加mutable即可正常编译。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 06:34:56