I had some nasty bugs when constructing lambdas in constructors when working with callback-based event system. Here's simple scenario:
class Object {
public:
int variable = 10;
std::function<void()> callback;
Object() {
callback = [this]() {
variable += 10;
};
}
};
class ObjectReceiver {
public:
Object object;
explicit ObjectReceiver(Object &&hi) : object(std::move(hi)) {}
};
int main() {
ObjectReceiver receiver{Object()};
receiver.object.callback();
std::cout << receiver.object.variable << std::endl;
return 0;
}
Here, "10" will be printed, because the object was moved, and pointer that lambda is holding, invalidated.
This means that in code outside of Object, i should always care, whether it constructs lambda in it's constructor.
How to deal with such problems? Should i make general convention for myself to not construct lambdas from constructors?
The problem is that the call
receiver.object.callback();is operating with an argumentthisthat points to the temporary instance ofObjectcreated by the constructorObject()inObjectReceiver receiver{Object()};. Even if you pass everything by value and avoid move semantics altogether you will still have the same problem. The underlying issue is thatthisis passed by value and not updated when move semantics are applied to copying the temporary instance ofObjectto the instance stored inreceiver.object.To make it work, you need to make the lambda relative to the instance of
Objectto which it applies with something like: