I have the following (simplified) code in my current project:
#include <iostream>
#include <string>
#include <functional>
#include <vector>
class Test{
public:
Test() = default;
Test(const Test& other) = delete;
Test& operator=(const Test& other) = delete;
Test(Test&& other) = default;
Test& operator=(Test&& other) = default;
void setFunction(){
lambda = [this](){
a = 2;
};
}
int callAndReturn(){
lambda();
return a;
}
private:
std::function<void()> lambda;
int a = 50;
};
int main()
{
Test t;
t.setFunction();
std::vector<Test> elements;
elements.push_back(std::move(t));
std::cout << elements[0].callAndReturn() << std::endl;
}
When I run it, the value 50 is printed instead of the expected value 2. I suppose this happens because the lambda function captures the current this
pointer. After the move operation the this
pointer changes and the function writes to the wrong a
.
Now my question is: Is there a way to change the lambda's captured reference to the new Test
so that the value 2 is printed?
If the lambda out lives the lifetime of the object that created it, the lambda can become invalid. This also means that the lambda can modify this without being declared mutable. It is the pointer which is const, not the object being pointed to. That is, unless the outer member function was itself a const function.
As the tasks performed by using function pointers are very small, hence it is not worth writing so many lines of code. Thus, Lambda expressions make it easier to do the same job. A Lambda expression is also called an anonymous function.
Lambdas can capture the this pointer which represents the object instance the outer function was called on. This is done by adding this to the capture list: When this is captured, the lambda can use member names of its containing class as though it were in its containing class. So an implicit this-> is applied to such members.
Such a lambda is not only a friend of that class, it has the same access as the class it is declared within has. Lambdas can capture the this pointer which represents the object instance the outer function was called on. This is done by adding this to the capture list:
The solution is not to capture this
at all. Instead, change your captured function type to accept it. And use a pointer to member (captured by value) for the indirect access to a
.
std::function<void(Test*)> lambda;
void setFunction(){
auto a = &Test::a;
lambda = [=](Test *t){
(t->*a) = 2;
};
}
int callAndReturn(){
lambda(this);
return a;
}
Live Example
As Galik noted, if you only need to access a single hard-coded member, then you don't even need that pointer to member. Thus the lambda can be capture-less:
void setFunction(){
lambda = [](Test *t){
t->a = 2;
};
}
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