Capture and move a unique_ptr in a c++14 lambda expression
15,163
Solution 1
The operator ()
of a lambda is const
by default, and you can't move from a const
object.
Declare it mutable
if you want to modify the captured variables.
auto lambda = [ capturedStr = std::move(str) ] () mutable {
// ^^^^^^^^^^
cout << *capturedStr.get() << endl;
auto str2 = std::move(capturedStr);
};
Solution 2
auto lambda = [ capturedStr = std::move(str) ] {
cout << *capturedStr.get() << endl;
auto str2 = std::move(capturedStr); // <--- Not working, why?
};
To give more detail, the compiler is effectively making this transformation:
class NameUpToCompiler
{
unique_ptr<string> capturedStr; // initialized from move assignment in lambda capture expression
void operator()() const
{
cout << *capturedStr.get() << endl;
auto str2 = std::move(capturedStr); // move will alter member 'captureStr' but can't because of const member function.
}
}
The use of mutable
on the lambda will remove the const
from the operator()
member function, therefore allowing the members to be altered.
Solution 3
To make the advice more explicit: add mutable
: http://coliru.stacked-crooked.com/a/a19897451b82cbbb
#include <memory>
int main()
{
std::unique_ptr<int> pi(new int(42));
auto ll = [ capturedInt = std::move(pi) ] () mutable { };
}
Related videos on Youtube
Comments
-
MartinMoizard about 2 years
I am capturing a unique_ptr in a lambda expression this way:
auto str = make_unique<string>("my string"); auto lambda = [ capturedStr = std::move(str) ] { cout << *capturedStr.get() << endl; }; lambda();
It works great until I try to move
capturedStr
to another unique_ptr. For instance, the following is not working:auto str = make_unique<string>("my string"); auto lambda = [ capturedStr = std::move(str) ] { cout << *capturedStr.get() << endl; auto str2 = std::move(capturedStr); // <--- Not working, why? }; lambda();
Here is the output from the compiler:
.../test/main.cpp:11:14: error: call to implicitly-deleted copy constructor of 'std::__1::unique_ptr<std::__1::basic_string<char>, std::__1::default_delete<std::__1::basic_string<char> > >' auto str2 = std::move(capturedStr); ^ ~~~~~~~~~~~~~~~~~~~~~~ ../include/c++/v1/memory:2510:31: note: copy constructor is implicitly deleted because 'unique_ptr<std::__1::basic_string<char>, std::__1::default_delete<std::__1::basic_string<char> > >' has a user-declared move constructor _LIBCPP_INLINE_VISIBILITY unique_ptr(unique_ptr&& __u) _NOEXCEPT ^ 1 error generated.
Why isn't it possible to move
capturedStr
?-
T.C. over 9 yearsLambdas'
operator ()
isconst
unless it's declaredmutable
, and you can't move from aconst
object. -
MartinMoizard over 9 yearsThanks @T.C., can you write an answer, I'll accept it
-
-
sehe over 9 yearsI thought you weren't gonna post :) +1