class A
{
int x;
public:
A(){}
~A()
{
cout<<this<<endl<<"bye"<<endl;
}
};

int main()
{

A a; 
a.~A();//bye

return 0;
    // after return 0, destructor will be called and bye will be printed again
}

the destructor gets called twice. The 1st time, its explicitly called and the second time, its called
after return 0.
in both the cases, the same addr of 'this' is printed.

As a destructor releases memory for an object, here it seems to be freeing the 'this' pointer
twice , which should cause a problem. However, the program executes smoothly.

Can some one explain this ?

> As a destructor releases memory for an object ...
a destructor does not release memory. it deinitializes an object and after it executes, what is left is uninitialized memory (earlier occupied by the object, whose lifetime is now over). how (or if) this memory is released depends on the object's storage duration.
try this out:

#include <iostream>
#include <cstdlib>

struct A
{
  static inline void* operator new( std::size_t sz )
  {
    void* memory = std::malloc(sz) ;
    std::cout << "allocated memory at address " << memory << '\n' ;
    return memory ;
  }
  static inline void operator delete( void* memory )
  {
    std::cout << "release memory at address " << memory << '\n' ;
    std::free( memory ) ;
  }
  A() { std::cout << "construct object at address " << this << '\n' ; }
  ~A() { std::cout << "destroy object at address " << this << '\n' ; }
};

int main()
{
  A* pa = new A ;
  delete pa ;
  std::cout << "--------------\n" ;
  A object ;
}

> However, the program executes smoothly.
memory is not released twice; that does not mean that the program is correct. it results in undefined behaviour.

Once a destructor is invoked for an object, the object no longer exists; the behavior is undefined if the destructor is invoked for an object whose lifetime has ended. [Example: if the destructor for an automatic object is explicitly invoked, and the block is subsequently left in a manner that would ordinarily invoke implicit destruction of the object, the behavior is undefined. ]

IS 12.4/14

a destructor can be explicitly invoked; but there are only a few situations where this is either required or would be right.

[Note: explicit calls of destructors are rarely needed. One use of such calls is for objects placed at specific addresses using a new-expression with the placement option. Such use of explicit placement and destruction of objects can be necessary to cope with dedicated hardware resources and for writing memory management facilities. For example,

void* operator new(size_t, void* p) { return p; }
struct X {
// ...
X(int);
~X();
};
void f(X* p);

void g() // rare, specialized use:
{
char* buf = new char[sizeof(X)];
X* p = new(buf) X(222); // use buf[] and initialize
f(p);
p->X::~X(); // cleanup
}

--- end note]

IS 12.4/13

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.