'Capture and move a unique_ptr in a c++14 lambda expression
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?
Solution 1:[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:[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:[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 { };
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | T.C. |
| Solution 2 | Remy Lebeau |
| Solution 3 | sehe |
