Is it undefined behavior to be destroying/deleting a std::function while in the middle of invocation?
class Event {
public:
Event(std::function<void()> f) : func(std::move(f)) {}
~Event() {}
std::function<void()> func;
};
int main()
{
std::vector<Event> events;
auto func = [&]() {
events.pop_back();
std::cout << "event" << std::endl;
// do more work
};
events.emplace_back(std::move(func));
events[0].func();
return 0;
}
The stored callable object is called the target of std::function . If a std::function contains no target, it is called empty.
When delete is used to deallocate memory for a C++ class object, the object's destructor is called before the object's memory is deallocated (if the object has a destructor). If the operand to the delete operator is a modifiable l-value, its value is undefined after the object is deleted.
So delete is for managing the dynamic memory, but the destructor is a method of the class itself, which is always called when the object is getting freed from the memory (stack or heap).
This is undefined by [res.on.objects]p2:
If an object of a standard library type is accessed, and the beginning of the object's lifetime does not happen before the access, or the access does not happen before the end of the object's lifetime, the behavior is undefined unless otherwise specified.
The "access" in this case consists of the call to the function call operator of the std::function
. The std::function
object's lifetime ended at the pop_back()
call, in the middle of the access. Therefore, the access does not happen before the end of the object's lifetime, and the behavior is undefined.
Your code (the bit you're asking about, i.e. the destructing of the object inside a member function) is roughly equivalent to
struct A
{
void f() { delete this; }
}
int main()
{
A* a = new A;
a.f();
}
This does actually work. Refcounted resources could do something similar when the refcount reaches zero in their unref
function.
Note you might want to rethink tying the event list and events themselves together like this. An event shouldn't know about its environment (the event queue).
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