При перемещении 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
};
}
- Почему это происходит?
- Можно ли захватить
std::unique_ptr
по-другому, что позволяет звонитьreset()
в лямбде (с C++17 или позже)?
4 ответа
- Почему это происходит?
Потому что оператор вызова функции лямбды,
Если только ключевое слово
mutable
был использован в лямбда-выражении, оператор вызова функции является const-квалифицированным, и объекты, которые были захвачены копией, не модифицируются изнутри этогоoperator()
,
а также
- Можно ли захватить
std::unique_ptr
по-другому, что позволяет позвонитьreset()
в лямбде
Вы должны отметить это mutable
,
mutable: позволяет body изменять параметры, захваченные копией, и вызывать их неконстантные функции-члены
например
auto l = [v = std::move(u)]() mutable {
v.reset();
};
- Почему это происходит?
Потому что лямбды по умолчанию не изменяемы. Поэтому все захваченные объекты являются постоянными. reset
является неконстантной функцией-членом, которая изменяет уникальный указатель.
- Можно ли перехватить 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();
};
}