0
#include <iostream>

struct ABC{
    int A;
    ABC(int i = 1) : A(i) {}
    ~ABC() {
        std::cout << A << std::endl;
    }
    void destruct() {
        delete this;
    }
};

int main() {
    ABC A1(2);
    A1.destruct();
    return 0;
}

Output:
2
2

I have this code in which I'm trying to manually delete structure variable. Doing so, I realized the destructor gets called twice here. Why is this happening? Why isn't it getting deleted when destruct() is called?

hjjg200
  • 335
  • 2
  • 11

4 Answers4

6

The delete this call causes undefined behaviour, which means that anything at all can happen.

delete may only be used for objects created by new.


For automatic objects with a non-trivial destructor (e.g. your A1), it is not possible to "destroy them early" unless you also create another ABC in the same place before the scope ends. In other words you can't "turn off" the destruction process that occurs when the scope ends.

Community
  • 1
  • 1
M.M
  • 138,810
  • 21
  • 208
  • 365
  • You could trigger the early destruction of an automatic object by forcing it to go out of scope early. You can do that by wrapping a the code block that declares, initializes and uses the automatic object in { }. However I am not sure an optimizing compiler may not delay the destruction until later. – P. Kouvarakis May 25 '16 at 10:03
  • @P.Kouvarakis by "early" I mean "before the end of its scope" . – M.M May 25 '16 at 10:04
  • Yes, I understood that and I think we both agree. I was just pointing out that you may be able to end the scope earlier than you think. Many people tend to only use { } to define code blocks for loops, functions etc, and forget that they can use it to define variable scope. – P. Kouvarakis May 25 '16 at 10:10
2

This is RAII working plus you committing suicide on an object. Calling the destructor on an object is almost always wrong! And calling the destructor twice is always wrong, as it invokes undefined behaviour.

You have to understand that C++ is handling memory for you, if you just let it:

struct Foo{};
int main() {
    Foo f;               // automatic storage, gets destroyed
                         // when object gets out of scope

    Foo* g = new Foo();  // heap allocated
    delete g;            // only here you have to delete
}

Just remember: Do not delete anything that you did not create via new (thanks to Mike Vine for the comment). And do not use (naked) heap allocation unless you need to.

463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
  • `delete` does two things: call the destructor, *and* release memory . It's possible to call the destructor without releasing memory (which will also lead to UB for a different reason to releasing memory) – M.M May 25 '16 at 10:03
  • @M.M thanks for pointing that out. I knew that I was oversimplifying a bit. I changed "...here you have to call destructor" with "...here you have to delete" to make it a bit less wrong ;) – 463035818_is_not_an_ai May 25 '16 at 12:30
2

Why isn't [my object] getting deleted when destruct() is called?

When an object gets destructed in C++, it does not mean that the object disappears. It means that the clean-up code from the destructor gets executed, and that any access to the object's members from that point on is invalid.

When you call destruct() you try to free object's memory by calling delete. This is undefined behavior in itself, because you have not allocated the object with new. This call causes the first printout.

However, since your object is in automatic memory, C++ is required to call its destructor when the object gets out of scope. This is the call that causes the second printout.

Note: You can fix your code by allocating A1 in dynamic memory:

int main() {
    ABC *A1 = new ABC(2);
    A1->destruct();
    return 0;
}

Now you get a single printout (demo). However, the practice of hiding delete in a member function is questionable.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • `delete this;` is used in the idiom of objects that manage their own reference count – M.M May 25 '16 at 10:05
1

Two points to consider here :-

1) Destructor for stack objects will always be called when they go out of scope. So no need to worry for their deallocation.

2) You cannot & should not use delete on the object allocated on stack. In general, you should not use delete this as long as you are not sure that this will be executed only as a consequence of deleting heap objects and after that you are not referring to that object.

ravi
  • 10,994
  • 1
  • 18
  • 36