Can a method called from an object delete the object?

Advertisements

I’m having a bit of confusion trying to understand what’s happening here.
If a class object calls a method which then in tern destroys the object, then the method should never return and the object should be destroyed right away and the destructor be called immediately.. Right? But instead the code just crashes.. So is an object not allowed to a call a method to delete itself? I’m assuming from how the callstack works, the pointer to the object would be destroyed hence when the function returns back to the caller the pointer is no longer valid when invoking further down the callstack?

class Foo
{
public:
    virtual void Run()
    {
        printf("Entering callback\n");
        RunSomeCallback();
        printf("We're back from callback\n");
    }
    virtual void RunSomeCallback() = 0;
    
    virtual ~Foo()
    {
        printf("We're Destroyed\n");
    }
};

Foo* f = nullptr;

void DestroyFoo();

class Bar : public Foo
{
public:
    virtual void RunSomeCallback()
    {
        printf("Inside callback\n");
        DestroyFoo();
    }
};


void DestroyFoo()
{
    printf("Deleting foo\n");
    delete f;
}
int main()
{
    f = new Bar();
    f->Run();
    return 0;
}

Then the behavior seems to change when I run the code with shared_ptr, but in this case the destructor is called before it prints "We’re back from callback", the code runs but is that then undefined behavior?

class Foo
{
public:
    virtual void Run()
    {
        printf("Entering callback\n");
        RunSomeCallback();
        printf("We're back from callback\n");
    }
    virtual void RunSomeCallback() = 0;
    
    virtual ~Foo()
    {
        printf("We're Destroyed\n");
    }
};

std::shared_ptr<Foo> f;

void DestroyFoo();

class Bar : public Foo
{
public:
    virtual void RunSomeCallback()
    {
        printf("Inside callback\n");
        DestroyFoo();
    }
};


void DestroyFoo()
{
    printf("Deleting foo\n");
    f = nullptr;
}
int main()
{
    f = std::make_shared<Bar>();
    f->Run();
    return 0;
}

Order of prints

Entering callback
Inside callback
Deleting foo
We're Destroyed
We're back from callback

So is the object not actually destroyed until all its methods are complete?

>Solution :

There is no problem with an object being destroyed while a member function is still executing on it (regardless of where in the call stack).

However, after the object’s lifetime has ended with the destructor call inoked from delete, no function, not even the member function that is still running, may access any member of the object and the memory used by the object may be reused by other objects as well. (Technically it is also implementation-defined whether reading this at all is still allowed, but practically that is fine as long as this isn’t dereferenced anymore.)

In your example code no members are accessed after delete (including the destructor) is called, so the program has defined behavior and the output you gave is expected. The destructor is called by delete, ending the objects lifetime, and then Foo::Run continues execution without ever touching the object again.

That’s true for both code snippets. Setting the std::shared_ptr to nullptr is effectively also just deleteing the object.


If this causes a crash on your system, then I would suspect a compiler bug

Leave a ReplyCancel reply