Reputation: 1301
Let's say I have the following scenario where I define a callback function m_deleter
.
class B {
public:
B() = default;
~B(){
if (m_deleter) {
m_deleter();
}
}
std::function<void()> m_deleter = nullptr;
};
class A {
public:
void createB(B& b) {
auto func = [this]() {
this->printMessage();
};
b.m_deleter = func;
}
void printMessage() {
std::cout << "Here is the message!" << std::endl;
}
};
And here is our main function:
int main() {
B b;
{
A a;
a.createB(b);
} // a falls out of scope.
}
Here is my confusion. When the stack instance a
falls out of scope, is the memory not deallocated? How can the this
pointer, used here in the callback: this->printMessage();
still point to a valid object?
When I run the above program, it prints:
Here is the message!
Edit:
Follow up question, is there any way for b
to know that a
has fallen out of scope and is no longer a valid object, and therefore should not call the callback?
Upvotes: 0
Views: 113
Reputation: 238461
When the stack instance a falls out of scope, is the memory not deallocated?
The storage duration has ended. The compiler is free to use its memory for other objects.
How can the this pointer, used here in the callback
It can't be used. Attempting to use it will result in undefined behaviour.
still point to a valid object?
It doesn't point to a valid object.
Edit: Follow up question, is there any way for b to know that a has fallen out of scope
You know that it has fallen out of scope by virtue of knowing that the program has exited the scope. There is no general way to test within the program, whether an object has been destroyed or not. You could enable certain tools such as undefined behaviour sanitiser and address sanitiser, which will terminate the program and tell you that you've attempted to use an invalid pointer.
What you must do, is structure the program in such way that it becomes impossible for the pointer to become invalid until it's no longer being used. It's not a trivial task, but it is achievable by following safe patterns, and by paying close attention when ever you use indirection.
Upvotes: 2
Reputation: 6600
It doesn't. But due to the fact that in the method printMessage
you don't reference any fields from the class A
, there is no crush. This is an UB however.
Here is the code that avoids this issue but demonstrates the correct behavior:
class A {
public:
void createB(B& b) {
auto func = []() {
A::printMessage();
};
b.m_deleter = func;
}
static void printMessage() {
std::cout << "Here is the message!" << std::endl;
}
};
No pointer, no references to any field, no need to track whether the instance is valid, no UB. If you need to access the data from A
, you need a valid instance.
Upvotes: 1