When I capture an object by reference in a C++11 lambda, let the object go out of scope, and then execute the lambda, it still has access to the object. When I execute the following code, the lambda call can still access the object, although the destructor has already been called! Can someone explain why this works and why I don't get a runtime error?
#include <iostream>
class MyClass {
public:
int health = 5;
MyClass() {std::cout << "MyClass created!\n";}
~MyClass() {std::cout << "MyClass destroyed!\n";}
};
int main(int argc, const char * argv[])
{
std::function<bool (int)> checkHealth;
if(true) {
MyClass myVanishingObject;
checkHealth = [&myVanishingObject] (int minimumHealth) -> bool {
std::cout << myVanishingObject.health << std::endl;
return myVanishingObject.health >= minimumHealth;
};
} // myVanishingObject goes out of scope
// let's do something with the callback to test if myVanishingObject still exists.
if(checkHealth(4)) {
std::cout << "has enough health\n";
} else {
std::cout << "doesn't have enough health\n";
}
return 0;
}
Here's the output:
MyClass created!
MyClass destroyed!
5
has enough health
According to the cppreference.com website's documentation of lambda functions
Dangling references
If an entity is captured by reference, implicitly or explicitly, and the function call operator of the closure object is invoked after the entity's lifetime has ended, undefined behavior occurs. The C++ closures do not extend the lifetimes of the captured references.
In other words, the fact that you have captured the object by reference and then let the object's lifetime ends means that invoking the lambda causes undefined behavior. Since one possible way that UB might work is "the object appears to be alive and well even though the object is dead," I suspect that you are seeing undefined behavior manifesting itself as nothing appearing to have gone wrong.
I suspect this would be the case if the compiler allocated a unique stack location to the temporary variable. This would mean that after the lifetime of the object ends, before main
returns, the memory wouldn't be touched by anything. Accordingly, you'd see the variable holding the value 5
just as before, since nothing else is writing on top of it.
Hope this helps!
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