为啥我不能在 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<int>
的已删除构造函数,这更有意义。
@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<int>
。当您执行move
转换时,它会转换为const std::unique_ptr<int>&&
。这就是您收到有关删除限定符的编译错误的原因:您正在尝试将 const 右值引用转换为非 const 右值引用。该错误可能没有它应有的帮助,但归根结底是:你不能move
const unique_ptr
。
mutable
修复了 - operator()
不再是 const
,因此该问题不再适用。
注意:如果您的Clean()
使用unique_ptr<int>
而不是unique_ptr<int>&&
,这更有意义(因为它是一个更明确、确定性的接收器),那么错误会更加明显:
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
需要复制,调用<Sig>
并销毁。然而,如果你正在做线程的事情,packaged_task<R>
是只能移动的,并且会为你生成期货。以上是关于为啥我不能在 C++14 的 lambda 中移动 std::unique_ptr?的主要内容,如果未能解决你的问题,请参考以下文章
在 c++14 lambda 表达式中捕获和移动 unique_ptr
为啥我不能将 lambda 传递给这个需要 std::function 的函数? [复制]