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

Why can't I move the std::unique_ptr inside lambda in C++14?

我想在 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 中遇到错误:

error: binding of reference to type 'unique_ptr<[2 * ...]>' to a value of type 'unique_ptr<[2 * ...]>' drops qualifiers

但是我一开始没有看到任何预选赛,尤其是掉线。

此外,我在邮件列表中发现了类似的 report,但没有得到答复。


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

您需要制作内部 lambda mutable:

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

operator() 默认为 const,因此您无法在该调用中修改其成员。因此,内部 list 的行为就好像它是 const std::unique_ptr<int> 一样。当您执行 move 转换时,它会转换为 const std::unique_ptr<int>&&。这就是为什么您会收到有关删除限定符的编译错误的原因:您正在尝试将 const 右值引用转换为非 const 右值引用。该错误可能没有它应有的帮助,但这一切都归结为:你不能 move a 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
    ^