The destructor for the class member `B`, why is it invoked in the snippet below?

106 views Asked by At

From §5.3.5[expr.delete]/1, I can understand that the destructor for the object *a is not invoked in the snippet below. But I didn't understand why is the destructor for the class member B invoked in this case, as can be seen in this live example.

#include <iostream>
class A
{
public:
   class B{ public: ~B(){ std::cout << "B dtor" << '\n'; } };
   A() { p = new B(); }
   operator B*() { return p; }
private:
   B* p;
};

int main()
{
   A* a = new A();
   delete *a;
   std::cout << "end" << '\n';
}

Would appreciate some quote from the Standard explaining this.

2

There are 2 answers

3
AnT stands with Russia On BEST ANSWER

Your delete *a applies operator delete to a non-pointer expression *a of type A. The only way this can be legal is when type A is implicitly convertible to some pointer type.

5.3.5 Delete [expr.delete]

1 ... The operand shall have a pointer to object type, or a class type having a single non-explicit conversion function (12.3.2) to a pointer to object type.

2 If the operand has a class type, the operand is converted to a pointer type by calling the above-mentioned conversion function, and the converted operand is used in place of the original operand for the remainder of this section.

In this case your class A is implicitly convertible to B *, which is exactly what happens when you do delete *a.

In other words, your delete *a is actually interpreted as

delete (*a).operator B*();

It is B you delete in your code, not A. This is why the destructor of B is called.

If you wanted to destroy the A object, you'd have to do

delete a;

(note, no *). That would not call B's destructor.

0
Alexander Dalshov On

if you tried to implement smart pointer - then you probably should examine boost sources

in a nutshell smart pointer pattern provide the idea of some small object, that wrap original object and destroy it as it's not required.

for example very simple example, also without custom deleters and so on:

<template class T>
class scope_delete
{
 public:
   scope_delete(T* ptr) : p(ptr) {}
   ~scope_delete() { delete p; }
   T* operator->() { return p; }
 private:
   T * p;
};

// somewere in programm
{
  auto obj = scope_delete(new MyCLasss);
  obj->some_fun();
} // here stack object obj will be deleted and remove original object.

for detailed information you should read some books, or I've just google this article.