How would I catch a member variable by value when using C++11 lambda expressions?
Using the [my_member] syntax doesn't seem to work, and implicit capture uses the this pointer. What is need is a way to explicitly specify capture type of member variables. Is that possible?
My workaround for now is:
void member_function()
{
std::shared_ptr<my_member_class> my_member_copy = my_member; // this shouldn't be necessary
std::async([=]{ std::cout << *my_member_copy; });
// std::async([=]{ std::cout << *my_member_; }); // wrong, my member could be potentially out of scope
}
I don't think you can capture a member by value, you can capture this but since the member is part of this you'll be using a shared member and not a new variable.
Not knowing what type your member is something like this should work:
auto copy = my_member;
std::async([copy]{ std::cout << copy; });
I don't understand why you're using a shared_ptr in your example, if you want to capture by value surely shared_ptr is the last thing you should consider.
Unfortunately, I don't think there is a straight-forward way to do this, but I can think of a couple of ways to capture a member without making an extra copy.
The first option is similar to your example but uses a reference for the local variable:
void member_function()
{
std::shared_ptr<my_member_class> &my_member_ref = my_member;
// Copied by the lambda capture
std::async([my_member_ref]{ std::cout << *my_member_ref; });
}
Note that there is a bug in pre 4.6.2 versions of GCC that cause the value not to be copied. See Capturing reference variable by copy in C++0x lambda.
A second approach would be to use bind to make the copy:
void member_function()
{
// Copied by std::bind
std::async(std::bind([](const shared_ptr<my_member_class>& my_member){
std::cout << *my_member; }, my_member));
}
In this example, bind will make its own copy of my_member, and this copy will then be passed to the lambda expression by reference.
Since your question is about C++11 this is not really an answer, but in C++14 you can do like this:
void member_function()
{
std::async([my_member=my_member]{ std::cout << *my_member; });
}
It does the same thing as your own "work-around" (if my_member is a shared_ptr).
auto& copy = my_member;
std::async([copy]{ std::cout << copy; });
auto& (above) also works and obviates copying twice. Although this approach is more syntax than passing [this], it obviates passing into the closure a dependency on the object [this] points to.
Right now, I faced the same problem and solved it myself:
Capture the this pointer.
then write this->member syntax inside the lambda:
That is,
std::async([this]{ std::cout << this->my_member_; } );
// ^^^^ ^^^^^^ use this syntax
// |
// ^
// capture `this` as well
It works for me. I hope it should work for you too. However, I'm not completely satisfied with this knowledge. After my work, I'll look for the reason why this syntax is required, or it is a compiler bug. I'm using GCC 4.5.0 (MinGW).
Well, I found the following topic which says this pointer should be captured in order to use the member of the class.
Capturing this required to access member functions?
Related
Looking at various examples with lambda expressions, I came across unexpected behavior for me. In this code, I expect that the variables captured by value will not change inside the lambda. Code execution shows the opposite. Can someone give an explanation. Thanks.
#include <iostream>
#include <functional>
using namespace std;
class Fuu{
public:
Fuu(int v):m_property(v){}
void setProperty(int v ){m_property = v;}
std::function<void(int)> lmbSet {[=](int v){ m_property = v;}};
std::function<void(char *)> lmbGet {[=](char * v){ cout<< v << " "<< m_property << endl;}};
std::function<void()> lmb4Static {[=]{ cout<<"static: "<< s_fild << endl;}};
void call() const {
lmbGet("test") ;
}
static int s_fild ;
int m_property;
};
int Fuu::s_fild = 10;
int main()
{
Fuu obj(3);
obj.call();
obj.setProperty(5);
obj.call();//expect 3
obj.lmbSet(12);
obj.call(); //expect 3
obj.lmb4Static();
Fuu::s_fild = 11;
obj.lmb4Static(); //expect 10
return 0;
}
That is a common problem. Common enough that they deprecated the implicit capture of this in a lambda with = for C++20. When your code is doing is:
std::function<void(int)> lmbSet {[=](int v){ m_property = v;}};
It is effectively doing this:
std::function<void(int)> lmbSet {[this](int v){ this->m_property = v;}};
The lambda captures the this pointer by copy, not m_property at all.
In general, but formally in C++20, the preferred way to do this would be to explicitly copy this (in which case, no = is necessary, though you could):
std::function<void(int)> lmbSet {[this](int v){ m_property = v;}};
To make a copy of the current object and modify that copy, you'd need to dereference this (and then the capture is a copy of *this) and to modify it, you'd need to mark your lambda mutable:
std::function<void(int)> lmbSet {[*this](int v) mutable { m_property = v;}};
It doesn't seem very useful, but perhaps that helps explain what's going on.
[Note: it's not valid to copy *this until the construction completes, or it's copying an object before its lifetime starts, and that will result in undefined behavior.]
Capture by value only takes copies of local variables (none in your example) and this pointer. Capturing this by value is equivalent to capturing non-static data members by reference. Static member variables, like globals, are not captured at all - you are accessing them directly instead.
If you actually need to keep a copy of non-local data, you can do it using "generalized capture" syntax which was added in C++14:
[m_property=m_property](char * v){ cout<< v << " "<< m_property << endl;}
In this case [=] effectively just copies this as a pointer. Then, when you access data members in your closure the copy of this is dereferenced, and if you modify that member it modifies the original member. If you think about it, it isn't possible that [=] copies each member. You would have an infinite recursion of copies as each lmbSet would make a new copy of lmbGet, which in turn would make a new copy of lmbSet.
Note that this solution requires that the rule of 3/5/0 be applied. If you try to make a copy of an instance of Fuu, the captured this pointer will copied and point to the original instance and not to the new copy. In general, capturing this or pointers to data members in default member initializes should be avoided.
If I need to generate a lambda that calls a member function, should I capture by reference or capture 'this'? My understanding is that '&' captures only the variables used, but 'this' captures all member variable. So better to use '&'?
class MyClass {
public:
int mFunc() {
// accesses member variables
}
std::function<int()> get() {
//return [this] () { return this->mFunc(); };
// or
//return [&] () { return this->mFunc(); };
}
private:
// member variables
}
For the specific example you've provided, capturing by this is what you want. Conceptually, capturing this by reference doesn't make a whole lot of sense, since you can't change the value of this, you can only use it as a pointer to access members of the class or to get the address of the class instance. Inside your lambda function, if you access things which implicitly use the this pointer (e.g. you call a member function or access a member variable without explicitly using this), the compiler treats it as though you had used this anyway. You can list multiple captures too, so if you want to capture both members and local variables, you can choose independently whether to capture them by reference or by value. The following article should give you a good grounding in lambdas and captures:
https://crascit.com/2015/03/01/lambdas-for-lunch/
Also, your example uses std::function as the return type through which the lambda is passed back to the caller. Be aware that std::function isn't always as cheap as you may think, so if you are able to use a lambda directly rather than having to wrap it in a std::function, it will likely be more efficient. The following article, while not directly related to your original question, may still give you some useful material relating to lambdas and std::function (see the section An alternative way to store the function object, but the article in general may be of interest):
https://crascit.com/2015/06/03/on-leaving-scope-part-2/
Here is a good explanation of what &, this and the others indicate when used in the capture list.
In your case, assuming that all what you have to do is calling a member function of the instance that is actually referenced by the this of the method that is currently executing, put this in your capture list should be enough.
Capturing this and capturing by reference are two orthogonal concepts. You can use one, both, or none. It doesn't make sense to capture this by reference but you can capture other variables by reference while capturing this by value.
It's not a clear-cut situation where on is better than the other. Rather, the two (at least potentially) accomplish slightly different things. For example, consider code like this:
#include <iostream>
class foo {
int bar = 0;
public:
void baz() {
int bar = 1;
auto thing1 = [&] { bar = 2; };
auto thing2 = [this] { this->bar = 3; };
std::cout << "Before thing1: local bar: " << bar << ", this->bar: " << this->bar << "\n";
thing1();
std::cout << "After thing1: local bar: " << bar << ", this->bar: " << this->bar << "\n";
thing2();
std::cout << "After thing2: local bar: " << bar << ", this->bar: " << this->bar << "\n";
}
};
int main() {
foo f;
f.baz();
}
As you can see, capturing this captures only the variables that can be referred to via this. In this case, we have a local variable that shadows an instance variable (yes, that's often a bad idea, but in this case we're using it to show part of what each does). As we see when we run the program, we get different results from capturing this vs. an implicit capture by reference:
Before thing1: local bar: 1, this->bar: 0
After thing1: local bar: 2, this->bar: 0
After thing2: local bar: 2, this->bar: 3
As to the specifics of capturing everything vs. only what you use: neither will capture any variable you don't use. But, since this is a pointer, capturing that one variable gives you access to everything it points at. That's not unique to this though. Capturing any pointer will give you access to whatever it points at.
I want to dynamically change the behaviour of a method of a class, so I implemented these method calling the operator() of a std::function holding a copy of one lambda function, that depends on some values known only after the class construction, at a time.
The lambdas change the state of the class, so they reset a container holding the behaviours of all dynamic methods.
Executing the above idea I was not able to access the capture list of the lamba after resetting the container.
The following snippet reproduces the problem:
std::vector< std::function<void(std::string)> > vector;
int main() {
//Change class state when variable value will be known
std::string variableValue = "hello";
auto function = [variableValue](std::string arg) {
std::cout <<"From capture list, before: "<< variableValue << std::endl;
std::cout <<"From arg, before: " << arg << std::endl;
vector.clear();
std::cout << "From capture list, after: " << variableValue << std::endl;
std::cout << "From arg, after: " << arg << std::endl;
};
vector.push_back(function);
//Dynamic method execution
vector[0](variableValue);
return 0;
}
Producing output:
From capture list, before: hello
From arg, before: hello
From capture list, after:
From arg, after: hello
where variableValue is invalidated after vector was clean.
Is the capture list invalidation an expected result?
Is safe using any other local variable, not only in the capture list, after calling std::function destructor?
Is there a suggested way / pattern to accomplish the same behaviour in a safer way (excluding huge switches/if on class states)?
We can get rid of the std::function, lambda and vector for this question. Since lambdas are just syntactic sugar for classes with a function-call operator, your testcase is effectively the same as this:
struct Foo
{
std::string variableValue = "hello";
void bar(std::string arg)
{
std::cout <<"From capture list, before: "<< variableValue << std::endl;
std::cout <<"From arg, before: " << arg << std::endl;
delete this; // ugrh
std::cout << "From capture list, after: " << variableValue << std::endl;
std::cout << "From arg, after: " << arg << std::endl;
}
};
int main()
{
Foo* ptr = new Foo();
ptr->bar(variableValue);
}
The function argument is fine because it's a copy, but after delete this the member Foo::variableValue no longer exists, so your program has undefined behaviour from trying to use it.
Common wisdom is that continuing to run the function itself is legal (because function definitions aren't objects and cannot be "deleted"; they are just a fundamental property of your program), as long as you leave the encapsulating class's members well enough alone.
I would, however, advise avoiding this pattern unless you really need it. It'll be easy to confuse people as to the ownership responsibilities of your class (even when "your class" is autonomously-generated from a lambda expression!).
Is the capture list invalidation an expected result?
Yes.
Is safe using any other local variable, not only in the capture list, after calling std::function destructor?
Yes.
Is there a suggested way / pattern to accomplish the same behaviour in a safer way (excluding huge switches/if on class states)?
That's impossible to say for sure without understanding what it is that you're trying to do. But you could try playing around with storing shared_ptrs in your vector instead… Just be careful not to capture a shared_ptr in the lambda itself, or it'll never be cleaned up! Capturing a weak_ptr instead can be good for this; it can be "converted" to a shared_ptr inside the lambda body, which will protect the lambda's life for the duration of said body.
std::function's destructor destroys the object's target if the object is non-empty, where the target is the wrapped callable object.
In your case, the target is a lambda expression. When you use a lambda expression, the compiler generates a "non-union non-aggregate class type" that contains the captures-by-value as data members and has operator() as a member function.
When you execute vector.clear(), the destructors of its elements are run, and therefore the destructors of the closure's captures-by-value, which are member variables, are run.
As for captures-by-reference, "the reference variable's lifetime ends when the lifetime of the closure object ends."
So, it is not safe to access any capture, whether by value and by reference, after std::function's destructor runs.
What about the actual operator()? "Functions are not objects," so they don't have lifetimes. So, the mere execution of the operator() after the destructor has been run should be fine, as long as you don't access any captures. See the conditions under which one can safely delete this.
I just wrote a pretty big capture:
[this, &newIndex, &indexedDirs, &filters, &flags, &indexRecursion](){...
I use this lambda (indexRecursion) for a recursion with thoudands of elements and asked myself, if it would be more efficient to use the "global" capture [&]. Since I have no clue of the implementation of the capture I need some explanation. Please with background too.
Usually you can think of a lambda as equivalent to this:
class ANON {
int data;
public:
void operator ()(void) const {
cout << data << endl;
}
} lambda;
// auto lambda = [data]() {cout << data << endl;}
This should give you an idea of how capture is implemented. Capture all (be it by copy = or reference &) will probably be no more than syntactic sugar for specifying all used/available variables for capture in the current scope.
But since ...
[..] An implementation may define the closure type differently from what is described below provided this does not alter the observable behavior of the program other than by changing: [..] the size and/or alignment of the closure type [..]
[N4431 §5.1.2/3]
... it would be legal for an implementation to use some sort of "black magic" for capture all by reference lambdas and just use a pointer to the captured stack frame, rewriting accesses to the variables as accesses to some offset of that pointer:
class ANON {
void * stack_frame;
public:
void operator ()(void) const {
cout << *static_cast<int *>(stack_frame + 8) << endl;
}
} lambda;
So using & might (some day) be more efficient, but as already said this is implementation defined and this nothing to be relied upon.
Internally lambdas are /usually/ implemented as ad-hoc classes whose single instance object is constructed in the point of lambda definition and which are exposing a functor to be called later. So lambda performance should be compared with passing a method to a function using std::bind.
Captures aren't mystical entities as well. If captures are reference-captures, entities which they refer to are detroyed when go out of the scope as usual, so beware if your lambda isn't local: inside its body it may refer to object which have been destroyed already.
I have tried the following:
std::function<void ()> getAction(std::unique_ptr<MyClass> &&psomething){
//The caller given ownership of psomething
return [psomething](){
psomething->do_some_thing();
//psomething is expected to be released after this point
};
}
But it does not compile. Any ideas?
UPDATE:
AS suggested, some new syntax is required to explicitly specify we need to transfer the ownership to the lambda, I am now thinking about the following syntax:
std::function<void ()> getAction(std::unique_ptr<MyClass> psomething){
//The caller given ownership of psomething
return [auto psomething=move(psomething)](){
psomething->do_some_thing();
//psomething is expected to be released after this point
};
}
Would it be a good candidate?
UPDATE 1:
I will show my implementation of move and copy as following:
template<typename T>
T copy(const T &t) {
return t;
}
//process lvalue references
template<typename T>
T move(T &t) {
return std::move(t);
}
class A{/*...*/};
void test(A &&a);
int main(int, char **){
A a;
test(copy(a)); //OK, copied
test(move(a)); //OK, moved
test(A()); //OK, temporary object
test(copy(A())); //OK, copying temporary object
//You can disable this behavior by letting copy accepts T &
//test(move(A())); You should never move a temporary object
//It is not good to have a rvalue version of move.
//test(a); forbidden, you have to say weather you want to copy or move
//from a lvalue reference.
}
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);});
You cannot permanently capture a unique_ptr in a lambda. Indeed, if you want to permanently capture anything in a lambda, it must be copyable; merely movable is insufficient.
This could be considered a defect in C++11, but you would need some syntax to explicitly say that you wanted to move the unique_ptr value into the lambda. The C++11 specification is very carefully worded to prevent implicit moves on named variables; that's why std::move exists, and this is a good thing.
To do what you want will require either using std::bind (which would be semi-convoluted, requiring a short sequence of binds) or just returning a regular old object.
Also, never take unique_ptr by &&, unless you are actually writing its move constructor. Just take it by value; the only way a user can provide it by value is with a std::move. Indeed, it's generally a good idea to never take anything by &&, unless you're writing the move constructor/assignment operator (or implementing a forwarding function).
The "semi-convoluted" solution using std::bind as mentioned by Nicol Bolas is not so bad after all:
std::function<void ()> getAction(std::unique_ptr<MyClass>&& psomething)
{
return std::bind([] (std::unique_ptr<MyClass>& p) { p->do_some_thing(); },
std::move(psomething));
}
A sub-optimal solution that worked for me was to convert the unique_ptr to a shared_ptr and then capture the shared_ptr in the lambda.
std::function<void()> getAction(std::unique_ptr<MyClass> psomething)
{
//The caller given ownership of psomething
std::shared_ptr<MyClass> psomethingShared = std::shared_ptr<MyClass>(std::move(psomething));
return [psomethingShared]()
{
psomethingShared->do_some_thing();
};
}
I used this really dodgy workaround, which involves sticking the unique_ptr inside a shared_ptr. This is because my code required a unique_ptr (due to an API restriction) so I couldn't actually convert it to a shared_ptr (otherwise I'd never be able to get my unique_ptr back).
My justification for using this abomination is that it was for my test code, and I had to std::bind a unique_ptr into the test function call.
// Put unique_ptr inside a shared_ptr
auto sh = std::make_shared<std::unique_ptr<Type>>(std::move(unique));
std::function<void()> fnTest = std::bind([this, sh, input, output]() {
// Move unique_ptr back out of shared_ptr
auto unique = std::move(*sh.get());
// Make sure unique_ptr is still valid
assert(unique);
// Move unique_ptr over to final function while calling it
this->run_test(std::move(unique), input, output);
});
Now calling fnTest() will call run_test() while passing the unique_ptr to it. Calling fnTest() a second time will result in an assertion failure, because the unique_ptr has already been moved/lost during the first call.
One also need to know, that lambdas capturing unique_ptr cannot be converted into std::function because std::function requires that the callable object is copyable.
auto lambdaWithoutCapture = [](){return 1;}; //Can be std::function
auto lambdaWithCapture = [=](){return 1;}; //Can be std::function
auto lambdaWithCapture2 = [&](){return 1;}; //Can be std::function
auto lambdaWithCapture3 = [uptrProblematic = std::move(uptrProblematic)]() mutable {return 1;}; //Can't be std::function
Therefore, if you don't have to specify return type of the function, you can use such approach which does not use std::function. But you need to know, that this will only work in local scope. You can't declare auto workerFactory(); in header file, as this will raise compilation error.
auto workerFactory()
{
std::unique_ptr uptrProblematic = std::make_unique<int>(9);
int importantData = 71;
return [=, uptrProblematic = std::move(uptrProblematic)](std::string input) mutable -> int {
std::cout << "Problematic variable is equal to: " << *uptrProblematic << "\n";
std::cout << "Important data is equal to: " << importantData << "\n";
std::cout << "Input equal to: " << input << "\n";
return 9;
};
}
int main()
{
auto worker = workerFactory();
worker("Test");
}