将unique_ptr移至lambda时,为什么无法调用reset?

时间:2019-07-04 15:37:24

标签: c++ c++11 lambda unique-ptr capture-list

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

4 个答案:

答案 0 :(得分:50)

  
      
  1. 为什么会这样?
  2.   

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

  

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

  
      
  1. 是否可以通过另一种方式捕获std::unique_ptr,从而允许在lambda中调用reset()
  2.   

您需要将其标记为mutable

  

可变:允许主体修改通过复制捕获的参数,并调用其非常量成员函数

例如

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

答案 1 :(得分:14)

  
      
  1. 为什么会这样?
  2.   

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

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

是的。声明可变的lambda:

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

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

答案 2 :(得分:8)

要变异Lambda的“成员”,您需要使用mutable关键字:

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

答案 3 :(得分:5)

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

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

#include <memory>

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