How to capture a unique_ptr into a lambda expression?
This issue is addressed by lambda generalized capture in C++14:
// a unique_ptr is move-only
auto u = make_unique<some_type>(some, parameters);
// move the unique_ptr into the lambda
go.run([u = move(u)]{do_something_with(u);});
Capture and move a unique_ptr in a c++14 lambda expression
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);
};
How to capture std::unique_ptr by move for a lambda in std::for_each
Update: you can capture a movable variable in a lambda from C++14 onwards.
std::for_each(arr.begin(), arr.end(), [p=std::move(p)](int& i) { i+=*p; });
You cannot capture a movable variable into a lambda in any straightforward way in C++11.
Lambdas capture by copy or by reference. Thus, to capture a move-only variable, you have to wrap it in an object where copying => moving (such as std::auto_ptr
). This is a nasty hack.
In your example, you can just capture by reference, but if this was just simplified code it may not do what you wanted with the real code:
std::for_each(arr.begin(), arr.end(), [&p](int& i) { i+=*p; });
Here's a copy-move-only wrapper:
template<typename T>
struct move_on_copy_wrapper
{
mutable T value;
move_on_copy_wrapper(T&& t):
value(std::move(t))
{}
move_on_copy_wrapper(move_on_copy_wrapper const& other):
value(std::move(other.value))
{}
move_on_copy_wrapper(move_on_copy_wrapper&& other):
value(std::move(other.value))
{}
move_on_copy_wrapper& operator=(move_on_copy_wrapper const& other)
{
value=std::move(other.value);
return *this;
}
move_on_copy_wrapper& operator=(move_on_copy_wrapper&& other)
{
value=std::move(other.value);
return *this;
}
};
You can then use it like this:
int main()
{
std::unique_ptr<int> p(new int(3));
move_on_copy_wrapper<std::unique_ptr<int>> mp(std::move(p));
[mp]()
{
std::cout<<"*mp.value="<<*mp.value<<std::endl;
}
();
std::cout<<"p="<<p.get()<<", mp="<<mp.value.get()<<std::endl;
}
When moving a unique_ptr into a lambda, why is it not possible to call reset?
- Why does this happen?
Because the function-call operator of a lambda,
Unless the keyword
mutable
was used in the lambda-expression, the function-call operator is const-qualified and the objects that were captured by copy are non-modifiable from inside thisoperator()
.
and
- Is it possible to capture the
std::unique_ptr
in another way which allows to callreset()
within the lambda
You need to mark it mutable
.
mutable: allows body to modify the parameters captured by copy, and to call their non-const member functions
e.g.
auto l = [v = std::move(u)]() mutable {
v.reset();
};
How to return a lambda with a captured unique_ptr
As pointed out in comments - callable wrapped in std::function
has to copy constructible. So instead of returning function just return lambda itself like that:
auto get_func()
{
auto i = std::make_unique<int>(2);
return [i=std::move(i)]() {
return *i;
};
}
pass a lambda that captures a unique_pointer
std::function
must be both CopyConstructible and CopyAssignable, which means that it must be able to copy its target. Unfortunately, since your lambda is not copyable, you cannot store it in a std::function
.
You will have to resort to another implementation of callable type-erasure that works with movable-only objects.
Moving unique_ptr inside a lambda function gives me a compiler error on C++17
The issue is that lambda's operator ()
is declared const
and with the move you try to modify the unique pointer j
.
Declare it mutable via auto t = std::thread([j = std::move(job)]() mutable ...)
or pass the unique_ptr
as an argument to the lambda.
How to capture a unique_ptr in a std::function
std::function objects can all be copied
std::function
is a type-erasure object that supports copying the object stored.
When you store a std::unique_ptr
in a lambda, that lambda does not support being copied.
So std::function
quite rightly complains. It is a type that can be copied, and when passed in something is works out how to copy it. "I cannot copy it" isn't a valid answer; all std::function
s can be copied.
Industrial strength solution:
There are two common approaches to solve this problem. First, you store the std::function
's state in a std::shared_ptr
of some kind. Second, you write or find a non-copying std::function
and use that instead.
More "modern" std::function
replacement libraries support a number of useful things:
- function views, that do not own what they wrap.
- move-only function objects, that don't support copying.
- multiple-overload function objects, that support more than 1 signature at once.
- fixed-sized buffers, that fail to compile if there isn't enough automatic storage instead of heap allocating.
- trivially copyable function objects
I've personally had a need for every one of the above for various special purposes.
Then you'd use moveonly_function<void()>
when you don't need to copy the callable, and your code compiles.
However, this is probably too heavy for your needs right now.
A quick solution is:
template<class F>
auto make_shared_function( F&& f ) {
return
[pf = std::make_shared<std::decay_t<F>>(std::forward<F>(f))]
(auto&&...args)->decltype(auto)
{
return (*pf)( decltype(args)(args)... );
};
}
now whenever you run into this problem:
// This does not compile.
std::function<void()> func = make_shared_function([p = move(ptr)] { });
and the state of the callable object is now stored in a shared ptr.
Related Topics
Why Does Int Pointer '++' Increment by 4 Rather Than 1
The Procedure Entry Point _Gxx_Personality_V0 Could Not Be Located
Detecting Superfluous #Includes in C/C++
How Is "=Default" Different from "{}" for Default Constructor and Destructor
Is Floating-Point Addition and Multiplication Associative
Serializing a Class Which Contains a Std::String
How to Compile a 64-Bit Application Using Visual C++ 2010 Express
Elegant Solution to Duplicate, Const and Non-Const, Getters
How to Include Libraries in Visual Studio 2012
Why Use Std::Bind Over Lambdas in C++14
C++ Array - Expression Must Have a Constant Value
C/C++: Force Bit Field Order and Alignment
Why Does Const Imply Internal Linkage in C++, When It Doesn't in C
Efficiently Load a Large Mat into Memory in Opencv
Accessing Inherited Variable from Templated Parent Class
Advantages of Auto in Template Parameters in C++17