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

aby*_*s.7 18 c++ lambda move-semantics 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.
  });
}
Run Code Online (Sandbox Code Playgroud)

我在Clang 3.7.0中收到错误:

错误:将类型'unique_ptr <[2*...]>'的引用绑定到类型'unique_ptr <[2*...]>'的值会丢弃限定符

但是我没有看到任何限定词,尤其是掉线.

另外,我在邮件列表上找到了类似的报告,但没有回答.


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

Bar*_*rry 27

你需要做内在的lambda mutable:

[this](Pointer* list) {
  thread_pool.Push([this, list = std::unique_ptr<int>(list) ]() mutable {
                                                               ^^^^^^^^^
    Clean(std::move(list));
  });
};
Run Code Online (Sandbox Code Playgroud)

operator()const默认情况下,在lambdas上,因此您无法在该调用中修改其成员.因此,内部list表现得好像是一个const std::unique_ptr<int>.当你进行move演员表演时,它会转换为const std::unique_ptr<int>&&.这就是为什么你得到关于删除限定符的编译错误:你试图将const rvalue引用转换为非const rvalue引用.该错误可能没有帮助,因为它可以,但是这一切都归结为:你不能move一个const unique_ptr.

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

注意:如果你使用Clean()a unique_ptr<int>而不是a 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
    ^
Run Code Online (Sandbox Code Playgroud)

  • OTOH,错误信息是残暴的. (2认同)