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?
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;
}
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;
};
}