template <class X> void destroy(X *tp) { tp->X::~X(); }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
template <class X>
void destroy(X *tp)
{
	tp->X::~X();
}

void main( void )
{

int x=34;
destroy(&x);
cout<<"endaxei";

int k;
cin>>k;
}



i found this code..
what does this code do??
and why is this legal??
I suggest you make your questions a little more specific. If you are wondering about the 'tp->X::~X()' syntax, it is an explicit call to the destructor for the object passed to the destroy() function. This is not something you would normally do. Search google for "When Is It Necessary To Invoke A Destructor Explicitly? How Do I Do It?".
A short summary what happens when you execute:
 
Class* c = new Class();


1. a block of memory with the size sizeof(Class) gets allocated.
2. In this case the standard constuctor gets invoked turning the piece of memory into an instance of Class.
3. A pointer to the new class instance is stored in c.

This is what happens when you execute:
 
delete c;


1. The destructor of Class get's called. This is basically what the destroy template above does.
2. The memory pointed to by c is deallocated.

The standard constructor and the destructor for an int don't do anything.

Legality:
* it should compile and do no harm in this case.
* the call to destroy should be optimized away anyway since a destructor for an int does nothing
* It should be used with care (don't use it if there is no real need), because:

1
2
3
4
{
  Class c;
  destroy(&c); // destructor of c is called here
} // destructor of c is called here again! => possibly undefined behaviour 


A function termplate like destroy is useful in low level classes like a vector.
Example:
1
2
3
4
5
std::vector<Class> v; //1
v.reserve(100);      //2
v.push_back(Class(42));  //3
v.pop_back();  //4
v.push_back(Class(43));  //5 


After (1) no memory is even allocated.
After (2) memory to store at least 100 Elements has been allocated, but no constructors have been called! (remember new Class[100] calls the standard constructors for all 100 elements!)
After (3) the first element is now an instance of Class.
After (4) the last element has been destructed with a function like destroy but it's memory has not been released.
So, in (5) the same memory can be reused to construct another element.

To sum it up:
* Creation process is split in memory allocation (if not static or on the stack) and construction.
* Destruction process is split into calling the destructor (at end of block (stack), end of program(static), or delete when created by new) and memory deallocation.

To use only part of the creation or destruction process can be used to optimize things but is dangerous and can lead to hard to find errors.

So better don't use it ;-).

in the code here
1
2
3
4
void destroy(X *tp)
{
	tp->X::~X();
}


first question:
can we do tp->~X();

second question:
how can tp access ~int()

and if i understan well every int i an object of class int and has some functions.
one of them is ~int()
am i correct?
As the following example shows, 'tp->X::~X()' is not exactly the same as 'tp->~X'. The latter is generally preferred, because it respects virtual overrides of the destructor:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>
using namespace std;

template <class X> void destroy1(X *tp)
{
  tp->~X();
}

template <class X> void destroy2(X *tp)
{
  tp->X::~X();
}

struct A { virtual ~A() { cerr << "~A\n"; } };
struct B: A { virtual ~B() { cerr << "~B\n"; } };
struct C: B { virtual ~C() { cerr << "~C\n"; } };

int main()
{
  C x;
  B &y = x;
  destroy1(&x);
  destroy2(&y);
}



Your second question:
You can access ~int() through 'tp' because 'tp' is of type 'int *' since 'X' is set to 'int' in your template invocation. If 'X' was bount to 'long' you would be accessing ~long().

Your third question:
Yes, every object has at least an implicit destructor, even 'int'. But in the case of 'int' it is a trivial destructor that does nothing.

But please remember, no object may ever be destroyed twice, so if you call the destructor manually, you must make sure the object is never destroyed in the ordinary way. Note, I'm violating this rule in my example above.

Last edited on
in this example you mentioned here the destructor will be called 2 times or 4 times???
because when main ends will call again the destructors of x and y
or no??
Yes,

There is only one object 'x' of type 'C'.
'y' is an alias for 'x', so there is still only one object.

Then the following happens:
1) destroy1() destroys 'x'.
2) destroy2() destroys 'x', but '~C' is not called this time, because we effectively call B::~B(), because the alias has type B.
3) 'x' is destroyed in the ordinary way.

Therefore, ~A() gets called three times, ~B() gets called three times, and ~C() gets called two times.

If the program had been correct, it would have called each of the three destructors exactly once.
ok thank you very much..!!
Topic archived. No new replies allowed.