При перемещении unique_ptr в лямбду, почему нельзя вызвать сброс?

При переезде std::unique_ptr в лямбду не возможно позвонить 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 по-другому, что позволяет звонить reset() в лямбде (с C++17 или позже)?

4 ответа

Решение
  1. Почему это происходит?

Потому что оператор вызова функции лямбды,

Если только ключевое слово mutable был использован в лямбда-выражении, оператор вызова функции является const-квалифицированным, и объекты, которые были захвачены копией, не модифицируются изнутри этого operator(),

а также

  1. Можно ли захватить std::unique_ptr по-другому, что позволяет позвонить reset() в лямбде

Вы должны отметить это mutable,

mutable: позволяет body изменять параметры, захваченные копией, и вызывать их неконстантные функции-члены

например

auto l = [v = std::move(u)]() mutable {
    v.reset();
};
  1. Почему это происходит?

Потому что лямбды по умолчанию не изменяемы. Поэтому все захваченные объекты являются постоянными. reset является неконстантной функцией-членом, которая изменяет уникальный указатель.

  1. Можно ли перехватить std::unique_ptr другим способом, который позволяет вызывать reset() внутри лямбды (с C++17 или новее)?

Да. Объявите лямбда-переменную:

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

Это возможно начиная с C++11, где были введены лямбды. Все захваченные неконстантные объекты изменяемой лямбды являются неконстантными копиями.

Чтобы изменить "член" лямбды, вам нужен mutable ключевое слово:

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

Внутри лямбды его данные по умолчанию неизменны. Вам нужно добавить mutable спецификатор лямбда-выражения.

В качестве альтернативы, вы можете захватить unique_ptr по ссылке, как например:

#include <memory>

int main()
{
    auto u = std::unique_ptr<int>();
    auto l = [&v = u]{
        v.reset(); 
    };
}
Другие вопросы по тегам