When can an object of a class call the destructor of that class, as if it\'s a regular function? Why can\'t it call the constructor of the same class, as one of its regular
Another way to think about the restriction is that a constructor is not just another function. Consider its definition: unlike other functions, it has no return value, and it may have an initializer list. That it just happens to have most of the syntax of a function is kind of a coincidence; it really exists only for the purpose of initializing a new instance of an object.
I think you can explicitly call the destructor if you make sure that the instance is replaced/recreated with a call to placement new:
class c
{
public:
void add() ;
c();
~c() ;
};
int main()
{
c objC ;
objC.add() ;
objC.~c() ; // this line compiles
new (&objC) c; // placement new invokes constructor for the given memory region
}
I've never seen this in practice, but logically it should work (unless c's constructor can throw, in which case, I imagine, hell could break loose during stack unwinding).
However, what you probably want is just assignment:
objC = c();
If the destructor has side-effects that you are interested in, implement assignment using the copy-and-swap idiom which gets the destructor invoked for the "left-hand" value.
Who says you can't? You just have to know how.
void Foo::Bar() {
*this = Foo(); // Reset *this
}
By definition, a constructor is only called once, when the object is created. If you have access to an object, then it must have been created, so you're not allowed to call the constructor again - this is the reason why explicit constructor calls are not allowed. Similarly, destructors must only be called once, when the object is destroyed. If this could always done automatically, then the language would also forbid explicit destructor calls.
However, in some circumstances, you might want precise control over memory management, and the ability to explicitly create and destroy objects within memory that you are managing. For this purpose, the language provides "placement new" to create an object at an arbitrary location, and explicit destructor calls to destroy objects created this way. An explicit constructor call wouldn't be useful, since you need to be able to specify the location of the new object - so you get "placement new" instead. An explicit destructor call is sufficient, so there's no need to invent some sort of matching "placement delete".
So: there is no valid use for explicit constructor calls, so they are not allowed. There is a valid use for explicit destructor calls, so they are (syntactically) allowed, with the rule that you must only ever use them on objects that won't otherwise be destroyed, i.e. objects created using "placement new", and in that case call them exactly once. Using them in any other way, like so many C++ errors, will compile but give undefined behaviour.
Try this out :
obj.ClassName::ClassName() ; // it works in VC 6.0 compiler
If you really need to do something like this, just create an additional function and call it from outside AND from the constructor itself, but let's see what happens when you do need such a call:
#include<new>
class A
{
//members
};
int main()
{
//allocate buffer
char* buffer = new char[sizeof(A)];
//construct A on that memory space
A * ptrToA = ::new (buffer) A();
//destroy the object
ptrToA->~A();
//deallocate the buffer
delete[] buffer;
}
One instance where you can find placement new usage is the standard containers. The allocator takes in the responsibility to allocate the buffer (allocate member) and the objects are constructed over that buffer as they are added into the container. For example, when you do reserve on vector object, it reserves the space for N objects meaning allocates space for N objects but does not construct them. Then when you do push_back etc, to add elements, they are created over that buffer. Basically, it is a technique to reduce the overhead of repeated calls to memory allocation function. And then when done, the vector destructor would destroy the objects calling the destructor explicitly for all objects in it and then call the deallocate() function of the allocator to release the memory. Hope this helps.