views:

279

answers:

10

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 functions? Why does the compiler stops us from doing this?

For example:

class c
{
public:
   void add() ;
   c();
   ~c() ;
};

void main()
{
 c objC  ;
 objC.add() ;
 objC.~c() ; // this line compiles
 objC.c() ;  // compilation error
}
+3  A: 

A destructor must be called on an existing instance of a class - destructing the instance is what it does. A constructor creates a brand new instance of a class, so calling on an existing instance makes no sense.

This is similar to the way new and delete work:

int * p = new int;    // call to new needs no existing instance
delete p;             // call to delete requires existing instance

And note in your code, the object would be destroyed twice, once explicitly, and once implicitly at the end of its enclosing scope. You typically only explicitly call a destructor if you are doing something unusual, probably involving the use of placement new.

anon
why cant existing object call constructor as a regular function, why compiler stops us from doing that???Once object is created and when i call destructor explicitly, complier allows, but why compiler dont allow me to do same for constructor.compiler is stopping us from doing that coz of some reasons, i want to know that reason.
Vinayaka Karjigi
Constructor chaining though does make sense and several other languages support it (Java/C#) just not C++.
Martin York
That's the way the language was designed to work. If you want to construct an object on top of an earlier version, you probably need to use placement new.
anon
@Vinayaka: Because (like Neil indicates) that does not make any logical sense. The constructor sets an initial state. Calling the Constructor after the object is fully constructed makes no sense as you would be re-setting the state without regard for the current state and that could cause a whole heap of problems.
Martin York
Ya it will not make any sense, but knowing why things wont work in that way is not wrong. as per my understanding, system calls constructor, when we create object. So once object is ready, i should be able to call any function in that class, and constructor is also a function. if i call explicitly the constructor, why should compiler stops me, constructor is called by me but not by system. Once object is ready, why compiler stops from calling the constructor as regular function.The same compiler allows destructor to be called explicitly but not constructor!!!
Vinayaka Karjigi
A constructor is different from other functions in lots of ways - this just happens to be one of them. I'm afraid you have to live with it.
anon
@Martin York. I believe the new c++ (0x/1x) standard allows ctor chaining
KitsuneYMG
@Vinayaka, the constructor may look like any other function but it isn't, it's a constructor and can only be called by the system. It's part of the C++ language definition and that's all there is to say about it.
Lazarus
+2  A: 

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.

alemjerus
It's been a long time since I did any C++ but I don't recall needing to allocate buffer space to instantiate a class object. Is that Objective C or similar?
Lazarus
The buffer space doesn't have to be allocated dynamically, but it has to be valid, e.g `char buffer[sizeof(A)]; A* p = new(buffer) A;` This is not about instantiating an object, this is about instantiating an object at a particular place in memory, so that an explicit call to destructor would be valid.
visitor
@visitor: It must be dynamically allocated to fulfill alignment issues.
GMan
@Lazarus: you're right, normally you'd just instantiate objects, either directly or using `new`. But sometimes (such as when implementing a container) you need to separate memory allocation from object construction, and "placement `new`" is the mechanism for doing that.
Mike Seymour
A: 

The constructor is there "c()" used with new, i.e.

c objC = new c();

If you want to call your constructor outside of the actual construction of the class instance then you either haven't understood the purpose of the constructor or are trying to put functionality in there that shouldn't be there.

Lazarus
objC had better be a pointer
anon
why cant existing object call constructor as a regular function, why compiler stops us from doing that???Once object is created and when i call destructor explicitly, complier allows, but why compiler dont allow me to do same for constructor.compiler is stopping us from doing that coz of some reasons I guess, i want to know that reason.
Vinayaka Karjigi
ScaryAardvark
@Scary.I want to know why compiler dont allow for this. When destructor can be called explicitly, without any problem, why constructor can't be called.
Vinayaka Karjigi
Explicit destructor calls are only allowed to destroy objects created with placement new, which is *the* way to invoke the constructor explicitly on a piece of raw memory.
visitor
+1 : The C++ FAQ states as much.http://www.parashift.com/c++-faq-lite/dtors.html#faq-11.9
ScaryAardvark
A: 

you can invoke the constructor of an instance's class using typeof:

class c
{
public:
   void add() ;
   c();
   ~c() ;
};

void main()
{
 c objC  ;
 objC.add() ;
 objC.~c() ; // this line compiles (but is a bad idea)
 typeof objC otherObjC;  // so does this.
}

This does not affect the value of the instance objC, but creates a new instance otherObjC using objC's class constructor.

Note: this may do something you don't expect if the static type is a baseclass of the dynamic type of the instance you have.

Alex Brown
...resulting in destructor being invoked twice for objC. Besides, typeof is GCC's language extension, and with the parenthesis otherObjC is a function that returns a `c`.
UncleBens
I wondered if it was a gcc extension, thanks. Why do you say the destructor is called twice of objC? I'm pretty sure the destructor is called once for objC and once for otherObjC. I'll go check
Alex Brown
the double destruction comes from the fast that objC is automatic, and ~c is destructed explicity. That was in the original code - the only change I made was to the line he said didn't compile, I left the rest as-is (and broken).
Alex Brown
thanks for the point about the brackets - I have removed it and it now works correctly (if ~c is removed). two objects constructed, two destructed.
Alex Brown
But then it doesn't seem to have anything to do with OP's question. (In C++0x, you'll have decltype, and currently Boost.Typeof might be more portable. It also seems that with -std=c++0x support for typeof is removed.)
UncleBens
A: 

Try this out :

obj.ClassName::ClassName() ; // it works in VC 6.0 compiler

Ashish
news flash: VC 6.0 allows you to do things that are :gasp: non-standard.
caspin
+4  A: 

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.

visitor
A: 

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.

Bob Lied
But the destructor isn't just another function, either, yet you can call it.
UncleBens
The destructor is not like a function and not like a constructor. A destructor can be virtual a constructor not, however adding virtual to to a destructor is nothing like adding virtual to a method. That is just one of the differences.
caspin
+4  A: 

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.

Mike Seymour
+1 for the formal precise answer. A question like this should just be answered with "you can not, because ..."
bodom_lx
Thanks for this answer Mike :) This logically fits why explicit call to constructor is not allowed and why its allowed for destructor. Once again thanks for explaining in detail to my question :)
Vinayaka Karjigi
A: 

You are asking about a particular style of syntax more than a language limitation. C++ allows you to call an object's constructor or destructor.

c objC;
objC.~c();  // force objC's destructor to run
new(&objC); // force objC's constructor to run

Why did the language designers not use this syntax instead?

c objC;
delete(&objC) c; // force objC's destructor to run
new(&objC) c;    // force objC's constructor to run

Or why not:

c objC
objC.~c(); // force objC's destructor to run
objC.c();  // force objC's constructor to run

My opinion as to why they chose the syntax they did: The first alternative is more flexible than the second. I can call the constructor / destructor on any address not just an instance. That flexibility is needed for allocation, but not for destruction. Also the first option's delete seems to be very dangerous once virtual destructors get in to the mess.

caspin
A: 

Who says you can't? You just have to know how.

void Foo::Bar() {
  *this = Foo(); // Reset *this
}
MSalters
But this doesn’t call the constructor for `this`, it calls `operator =`.
Konrad Rudolph
Obviously not, no. But it calls the classes ctor from an instance of the clas. So it answers the question asked.
MSalters