【问题标题】:When moving a unique_ptr into a lambda, why is it not possible to call reset?将 unique_ptr 移入 lambda 时,为什么不能调用 reset?
【发布时间】:2023-04-03 07:37:01
【问题描述】:

std::unique_ptr 移动到 lambda 中时,无法在其上调用 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,允许在 lambda 中调用 reset()(使用 C++17 或更高版本)?

【问题讨论】:

  • 但是为什么呢?当 lambda 超出范围时,v 不会自动重置吗?
  • @L.F.是的,它的析构函数与const ptr 一起工作。但是,如果指针的生命周期需要在作用域结束之前结束(或者应该分配另一个指针或者应该将托管对象的所有权转移给另一个 unique_ptr),则需要一个非常量的 unique_ptr。跨度>

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


【解决方案1】:
  1. 为什么会这样?

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

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

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

您需要将其标记为mutable

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

例如

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

【讨论】:

    【解决方案2】:
    1. 为什么会这样?

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

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

    是的。声明 lambda 可变:

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

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

    【讨论】:

      【解决方案3】:

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

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

      【讨论】:

        【解决方案4】:

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

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

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

        【讨论】:

        • 很可能 lambda 会比它声明的范围更长寿,所以引用捕获会悬空
        • @Caleth 这取决于上下文。
        猜你喜欢
        • 2017-03-03
        • 2014-05-12
        • 2015-08-12
        • 1970-01-01
        • 2020-05-30
        • 2018-07-29
        • 1970-01-01
        • 2015-10-30
        • 2012-12-01
        相关资源
        最近更新 更多