35

进入std::unique_ptrlambda 时,无法调用reset()它,因为它似乎是 const :

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. 是否可以以另一种方式捕获std::unique_ptr允许reset()在 lambda 中调用(使用 C++17 或更高版本)?
4

4 回答 4

52
  1. 为什么会这样?

因为lambda的函数调用运算符,

除非mutable在 lambda 表达式中使用了关键字,否则函数调用运算符是 const 限定的,并且复制捕获的对象不能从 this 内部修改operator()

  1. std::unique_ptr是否可以以允许reset()在 lambda中调用的另一种方式捕获

你需要标记它mutable

mutable:允许body修改copy捕获的参数,并调用它们的non-const成员函数

例如

auto l = [v = std::move(u)]() mutable {
    v.reset();
};
于 2019-07-04T15:39:19.570 回答
14
  1. 为什么会这样?

因为 lambda 在默认情况下是不可变的。因此所有捕获的对象都是常量。reset是修改唯一指针的非常量成员函数。

  1. 是否有可能以另一种方式捕获 std::unique_ptr 允许在 lambda 中调用 reset() (使用 C++17 或更高版本)?

是的。声明 lambda 可变:

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

这是可能的,因为 C++11 引入了 lambda。所有捕获的可变 lambda 的非常量对象都是非常量副本。

于 2019-07-04T15:39:43.113 回答
8

要改变 lambda 的“成员”,您需要以下mutable关键字:

auto l = [v = std::move(u)] () mutable {
    v.reset();
};
于 2019-07-04T15:39:48.410 回答
4

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

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

#include <memory>

int main()
{
    auto u = std::unique_ptr<int>();
    auto l = [&v = u]{
        v.reset(); 
    };
}
于 2019-07-04T16:02:56.963 回答