为啥我不能在 C++14 的 lambda 中移动 std::unique_ptr?

Posted

技术标签:

【中文标题】为啥我不能在 C++14 的 lambda 中移动 std::unique_ptr?【英文标题】:Why can't I move the std::unique_ptr inside lambda in C++14?为什么我不能在 C++14 的 lambda 中移动 std::unique_ptr? 【发布时间】:2015-08-12 05:47:22 【问题描述】:

我想在 lambda 中传递一个原始指针,但如果未调用 lambda,我不希望它被泄露。它看起来像这样:

void Clean(std::unique_ptr<int>&& list);

void f(int* list) 
  thread_pool.Push([list = std::unique_ptr<int>(list) ] 
    Clean(std::move(list));  // <-- here is an error.
  );

我在 Clang 3.7.0 中遇到错误:

错误:将对“unique_ptr”类型的引用绑定到“unique_ptr”类型的值删除限定符

但我一开始没有看到任何限定词,尤其是被丢弃了。

另外,我在邮件列表中发现了类似的report,但没有答案。


我应该如何修改我的代码,使其编译并按语义预期工作?

【问题讨论】:

什么是Clean()?当我尝试在 clang 上重现时,假设 Clean() 采用 unique_ptr 的值,我得到“错误:调用 std::unique_ptr&lt;int&gt; 的已删除构造函数,这更有意义。 @Barry 在原始错误之后我没有预料到任何其他错误。现在我正在尝试修复所有其他问题并更新问题中的代码,以便原始错误将是唯一​​的错误。 【参考方案1】:

你需要使内部 lambda mutable:

[this](Pointer* list) 
  thread_pool.Push([this, list = std::unique_ptr<int>(list) ]() mutable 
                                                               ^^^^^^^^^
    Clean(std::move(list));
  );
;

operator() 在 lambdas 上默认是const,所以你不能在那个调用中修改它的成员。因此,内部list 的行为就好像它是const std::unique_ptr&lt;int&gt;。当您执行move 转换时,它会转换为const std::unique_ptr&lt;int&gt;&amp;&amp;。这就是您收到有关删除限定符的编译错误的原因:您正在尝试将 const 右值引用转换为非 const 右值引用。该错误可能没有它应有的帮助,但归根结底是:你不能moveconst unique_ptr

mutable 修复了 - operator() 不再是 const,因此该问题不再适用。

注意:如果您的Clean() 使用unique_ptr&lt;int&gt; 而不是unique_ptr&lt;int&gt;&amp;&amp;,这更有意义(因为它是一个更明确、确定性的接收器),那么错误会更加明显:

error: call to deleted constructor of `std::unique_ptr<int>`
note: 'unique_ptr' has been explicitly marked deleted here  

    unique_ptr(const unique_ptr&) = delete
    ^

【讨论】:

值得一提的是 lambda 本身变成了一个只能移动的对象,所以我需要在 thread_pool.Push() 内显式移动它。 @Abyss.7 没有理由明确移动 lambda:它是一个右值,除非你将它存储在某个地方。 @Yakk,是的,我已经意识到了。我还发现这样的 lambda 不能存储在 std::function 中 - 至少在 libc++ 和 libstdc++ 中。所以,现在整个想法对我来说似乎毫无意义,直到我实现自己的仅移动函子对象。 @abyss.7 是的,std::function 需要复制,调用&lt;Sig&gt; 并销毁。然而,如果你正在做线程的事情,packaged_task&lt;R&gt; 是只能移动的,并且会为你生成期货。

以上是关于为啥我不能在 C++14 的 lambda 中移动 std::unique_ptr?的主要内容,如果未能解决你的问题,请参考以下文章

在 c++14 lambda 表达式中捕获和移动 unique_ptr

为啥我不能将 lambda 传递给这个需要 std::function 的函数? [复制]

为啥以下代码编译失败(C++ lambda问题)

为啥 lambda init-capture 对 unique_ptr 不起作用?

为啥 lambda 函数默认会丢弃推导的返回类型引用?

为啥我不能在 lambda 中捕获这个引用('&this')?