I am learning the new features in c++11 and came across this problem. I'd like to capture an unique_ptr by moving it inside a lambda as an argument for for_each.
set up:
std::array<int,4> arr = {1,3,5,6};
std::unique_ptr<int> p(new int); (*p) = 3;
attempt 1 - doesn't work because unique_ptr doesn't have a copy constructor. c++0x doesn't specify the pass by move syntax.
std::for_each(arr.begin(), arr.end(), [p](int& i) { i+=*p; });
attempt 2 - use bind to bind a moved copy of p to a function that takes int&:
std::for_each(arr.begin(), arr.end(),
std::bind([](const unique_ptr<int>& p, int& i){
i += (*p);
}, std::move(p))
);
Compiler complains that 'result' : symbol is neither a class template nor a function template.
The main purpose of the exercise is to understand how a movable variable be captured in a lambda that's cached for later use.
A unique_ptr can only be moved. This means that the ownership of the memory resource is transferred to another unique_ptr and the original unique_ptr no longer owns it. We recommend that you restrict an object to one owner, because multiple ownership adds complexity to the program logic.
The mutable keyword is used so that the body of the lambda expression can modify its copies of the external variables x and y , which the lambda expression captures by value. Because the lambda expression captures the original variables x and y by value, their values remain 1 after the lambda executes.
Instances of std::function can store, copy, and invoke any CopyConstructible Callable target -- functions, lambda expressions, bind expressions, or other function objects, as well as pointers to member functions and pointers to data members.
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;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With