-2

I am trying to figure out in C++ the difference between delete operator and destructor and I tried use the following two snippets (I use visual studio 2019 to compile them) :

code 1:

#include <stdio.h>
class A
{
    public:
        A() { a = new int; *a = 42; b = 33; }
        ~A()
        {
            printf("destructor!\n");
            delete a;
        }

        int* a;
        int  b;
};

int main(int argc, const char** argv)
{
    A* myA = new A();
    printf("a:%d  b:%d\n", *(myA->a), myA->b);
    //delete myA;
    myA->~A();
    printf("b:%d\n", myA->b);
    printf("a:%d\n", *(myA->a));
}

code2: (almost the same with code 1, just change use delete to use desctructor)

#include <stdio.h>
class A
{
    public:
        A() { a = new int; *a = 42; b = 33; }
        ~A()
        {
            printf("destructor!\n");
            delete a;
        }

        int* a;
        int  b;
};

int main(int argc, const char** argv)
{
    A* myA = new A();
    printf("a:%d  b:%d\n", *(myA->a), myA->b);
    delete myA;
    //myA->~A();
    printf("b:%d\n", myA->b);
    printf("a:%d\n", *(myA->a));
}

The result of code 1 is : enter image description here

while running code 2 throws exception: enter image description here, and the console is : enter image description here

From the results I guess that when you run myA->~A(), it just execute the destructor defined, that is delete a, making this pointer a dangling pointer. when you run delete myA, it not will also execute destructor, and make pointer myA a dangling pointer. But I am not sure how exactly these are implemented.

The explanation of the difference of the two results is my first question

The second question is: the code snippet is copied from Here, and its result is also different from mine, hopefully if anyone can also explain this

Lake_Lagunita
  • 521
  • 1
  • 4
  • 20
  • 5
    did you read the answers on the question you link? They explain that the first version of the code has undefined behavior (second has UB as well for similar reasons), ie output could be anything. The answers also adress your first question – 463035818_is_not_an_ai Jun 14 '21 at 14:21
  • 2
    Does this answer your question? https://stackoverflow.com/questions/14215140/does-the-c-destructor-actually-delete-stuff. Why not? – 463035818_is_not_an_ai Jun 14 '21 at 14:23
  • 2
    Does this answer your question? https://stackoverflow.com/questions/16908650/what-is-the-difference-between-delete-and-calling-destructor-in-c – Drew Dormann Jun 14 '21 at 14:23
  • 1
    you should also try this variant `int main() { A a; }` – 463035818_is_not_an_ai Jun 14 '21 at 14:26
  • @463035818_is_not_a_number in your first link, the answer says "Calling a destructor releases the resources owned by the object, but it does not release the memory allocated to the object itself." I am not quite clear about the difference of resources vs the memory allocated to the object. – Lake_Lagunita Jun 14 '21 at 15:19

1 Answers1

1

delete myA; is a delete expression. If myA is not nullptr, it will first call the destructor of the object pointed to by myA (if the pointed type has a destructor), then it will release the storage used by the object which was previously allocated by a new expression.

myA->~A(); explicitly calls the destructor of the object pointed to by myA. It will not release the storage previously allocated. In this case, you are leaking the memory associated with the A. Unless you are using placement new (an advanced language feature which is not used in your example) then explicitly calling a destructor is almost certainly an error.

Regarding the output of printf("b:%d\n", myA->b); and printf("a:%d\n", *(myA->a)); in both examples these result in Undefined Behavior.

When you do delete myA; the pointer myA now has an invalid pointer value (often called "dangling pointer") which you are not allowed to dereference. In both printf you try myA-> which is Undefined Behavior, so the result is meaningless.

When you do myA->~A(); the pointer myA still points to valid storage, but it does not point to an A anymore. That A was destroyed. So, similarly, trying to dereference myA will also be Undefined Behavior, resulting in meaningless output.

It seems like you may be under the impression that if running your code doesn't produce a visible error, then it must be OK. But this is not true in C++. A lot of errors lead to Undefined Behavior which is not required to crash or give any clear diagnostic that something is wrong. The fact that the myA->~A(); example did not result in a runtime error for you does not mean it is any less incorrect than the example using delete myA;.

François Andrieux
  • 28,148
  • 6
  • 56
  • 87
  • Thank you for your explanation. If I would make an analogy, say, flying a kite, then delete myA means that the wire gets cut off, while call destructor myA->~A(); means that the kite itself is broken, not the wire ? – Lake_Lagunita Jun 14 '21 at 15:17
  • 2
    @LeonloveKaren No, not at all. `delete` includes calling the destructor. So whatever the destructor does in your analogy, the delete expression does that, and also does whatever the analogy's version of cleaning up memory is. – François Andrieux Jun 14 '21 at 15:35