При перемещении unique_ptr в лямбду, почему нельзя вызвать сброс?
При перемещении std::unique_ptr
в лямбду невозможно вызвать метод 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
};
}
- Почему это происходит?
- Можно ли
std::unique_ptr
другим способом, который позволяет вызывать reset()
внутри лямбды (с С++ 17 или новее)?
Ответы
Ответ 1
- Почему это происходит?
Потому что оператор вызова функции лямбды,
Если ключевое слово mutable
не использовалось в лямбда-выражении, оператор вызова функции является константно квалифицированным, и объекты, которые были захвачены копией, не модифицируются внутри этого operator()
.
а также
- Можно ли
std::unique_ptr
другим способом, который позволяет вызывать reset()
внутри лямбды?
Вы должны пометить его как mutable
.
mutable: позволяет body изменять параметры, захваченные копией, и вызывать их неконстантные функции-члены
например
auto l = [v = std::move(u)]() mutable {
v.reset();
};
Ответ 2
- Почему это происходит?
Потому что лямбды по умолчанию не изменяемы. Поэтому все захваченные объекты являются постоянными. reset
является неконстантной функцией-членом, которая изменяет уникальный указатель.
- Можно ли перехватить std :: unique_ptr другим способом, который позволяет вызывать reset() внутри лямбды (с С++ 17 или новее)?
Да. Объявите лямбда-переменную:
[captures](arguments) mutable { body }
^^^^^^^
Это возможно начиная с С++ 11, где были введены лямбды. Все захваченные неконстантные объекты изменяемой лямбды являются неконстантными копиями.
Ответ 3
Чтобы изменить "член" лямбды, вам нужно ключевое слово mutable
:
auto l = [v = std::move(u)] () mutable {
v.reset();
};
Ответ 4
Внутри лямбды его данные по умолчанию неизменны. Вам нужно добавить mutable
спецификатор к лямбда-выражению.
В качестве альтернативы вы можете захватить unique_ptr
по ссылке, например:
#include <memory>
int main()
{
auto u = std::unique_ptr<int>();
auto l = [&v = u]{
v.reset();
};
}