0

The following code work and prints out Dead. How does the call to callback_fn not cause a crash since destructor is obviously called?

#include <iostream>
#include <memory>
#include <functional>

class A {
  private:
    std::string message = "Alive";
  public:
    ~A() { message = "Dead"; }
    auto get_callback() { return [this](){ callback(); }; }
  private:
    void callback() const { std::cout << message << std::endl; }
};

int main()
{   
    std::function<void()> callback_fn;
    {
        A a;
        callback_fn = a.get_callback();
    }
    callback_fn();
}

Since this is captured by value:

  1. How does the member function call work after object destruction?
  2. Why isn't the memory of message being freed at a destruction?

If I write main like this, I get no output (which I suspect to be undefined behaviour). I would expect the same behaviour as the code abve.

int main()
{
    auto a = std::make_unique<A>();
    auto callback_fn = a->get_callback();
    a.reset();
    callback_fn();
}
Rudolf Lovrenčić
  • 147
  • 1
  • 2
  • 9
  • Related: [Is it legal to call member functions after an object has been explicitly destroyed but before its memory was deallocated?](https://stackoverflow.com/q/30310299/580083). – Daniel Langr Oct 30 '19 at 13:15
  • Possible duplicate of [Can a local variable's memory be accessed outside its scope?](https://stackoverflow.com/questions/6441218/can-a-local-variables-memory-be-accessed-outside-its-scope) – apple apple Oct 30 '19 at 13:19

1 Answers1

3

tl;dr - this code does what it does by pure accident

You are invoking undefined behaviour here. Anything could happen when you use object after its destruction. (Un)Luckily for you it works and prints your variable. But it might as well crash the program or summon demons straight from hell as it is invalid C++ code.

bartop
  • 9,971
  • 1
  • 23
  • 54
  • Is UD invoked when calling `callback_fn` function because `this` is pointing to freed memory or when I try to print `message`? – Rudolf Lovrenčić Oct 30 '19 at 13:27
  • 2
    @Garzet UB is when lambda, stored in `callback_fn`, it trying to invoke `callback()` member function for no-logner existing object. It would be UB even if `callback()` was an empty function `{ }`. – Daniel Langr Oct 30 '19 at 13:31