Mozbi
Mozbi

Reputation: 1479

Deleting a std::function in the middle of invocation

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

Upvotes: 6

Views: 607

Answers (2)

T.C.
T.C.

Reputation: 137315

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.

Upvotes: 6

rubenvb
rubenvb

Reputation: 76529

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).

Upvotes: 3

Related Questions