将 unique_ptr 移入 lambda 时,为什么无法调用重置?

When moving a unique_ptr into a lambda, why is it not possible to call reset?

std::unique_ptr 移动到 lambda 中时,无法对其调用 reset(),因为它似乎是常量:

error C2662: void std::unique_ptr<int,std::default_delete<_Ty>>::reset(int *) noexcept': cannot convert 'this' pointer from 'const std::unique_ptr<int,std::default_delete<_Ty>>' to 'std::unique_ptr<int,std::default_delete<_Ty>> &
#include <memory>
int main()
{
    auto u = std::unique_ptr<int>();
    auto l = [v = std::move(u)]{
        v.reset(); // this doesn't compile
    };
}
  1. 为什么会这样?
  2. 是否有可能以另一种允许在 lambda 中调用 reset() 的方式捕获 std::unique_ptr(使用 C++17 或更高版本)?
  1. Why does this happen?

因为 function-call 运算符 lambda,

Unless the keyword mutable was used in the lambda-expression, the function-call operator is const-qualified and the objects that were captured by copy are non-modifiable from inside this operator().

  1. Is it possible to capture the std::unique_ptr in another way which allows to call reset() within the lambda

您需要标记它mutable

mutable: allows body to modify the parameters captured by copy, and to call their non-const member functions

例如

auto l = [v = std::move(u)]() mutable {
    v.reset();
};
  1. Why does this happen?

因为默认情况下 lambda 是 non-mutable。因此所有捕获的对象都是常量。 reset是一个non-const修改唯一指针的成员函数。

  1. Is it possible to capture the std::unique_ptr in another way which allows to call reset() within the lambda (with C++17 or later)?

是的。声明 lambda 可变:

[captures](arguments) mutable { body }
                      ^^^^^^^

这是可能的,因为 C++11 引入了 lambda。可变 lambda 的所有捕获 non-const 个对象都是 non-const 个副本。

要改变 lambda 的 "member",您需要 mutable 关键字:

auto l = [v = std::move(u)] () mutable {
    v.reset();
};

在 lambda 中,它的数据成员默认是不可变的。您需要将 mutable 说明符附加到 lambda 表达式。

作为替代方案,您可以通过引用捕获 unique_ptr,例如:

#include <memory>

int main()
{
    auto u = std::unique_ptr<int>();
    auto l = [&v = u]{
        v.reset(); 
    };
}