views:

467

answers:

8

is it possible to re-initialize an object of a class using its constructor?

+7  A: 

No, constructors are only called when the object is first created. Write a new method to do it instead.

Edit

I will not acknowledge placement new, because I don't want to have to get a pet raptor for work.

See this comic, but think of the topic on hand...

Dan McGrath
+14  A: 

Sort of. Given a class A:

A a;
...
a = A();   

the last statement is not initialisation, it is assignment, but it probably does what you want.

anon
+1 Of course this also requires writing a complete, correct assignment operator.
Greg Hewgill
@Greg This requires HAVING a correct assignment operator, not necessarily WRITING one - the default will often be perfectly OK.
anon
+4  A: 

Short answer:

No. If part of your object's intended behavior is to be initialized several times, then the best way to implement this is through an accessible initialization method. The constructor of your class can simply defer to this method.

class C1 {
public:
  C1(int p1, int p2) {
    Init(p1,p2);
  }
  void Init(int p1, int p2) { ... }
};

Nitpicker corner:

Is there some incredibly evil way to call a constructor in C++ after an object is created? Almost certainly, this is C++ after all. But it's fundamentally evil and it's behavior is almost certainly not defined by the standard and should be avoided.

JaredPar
You could do: `T x; x->~T(); new (` I'm not sure how defined that is, it almost seems ok. (Ok as in legal, not ok as in this is totally awesome code.)
GMan
@GMan, I visibly shuddered when I read that :)
JaredPar
+9  A: 

It's possible, although it's a very bad idea. The reason why is that without calling the destructors on the existing object, you are going to leak resources.

With that major caveat, if you insist on doing it, you can use placement new.

// Construct the class
CLASS cl(args);

// And reconstruct it...
new (&cl) CLASS(args);
R Samuel Klatchko
You should get a -1 just for suggesting it to someone :P, but a +1 for the hack -- didn't know it, so 0 in total
Kornel Kisielewicz
One could `cl->~CLASS();` prior to placement new, as I said on Jared's answer. I'm not sure if that's defined, seems legal.
GMan
+1, only right solution. Nothing evil, it's the way how it's done.
Alexander Gessler
@Alexander: As the answer stands, it's evil and undefined.
GMan
No, the solution is not correct. It is critical to remember to destruct the "old" object first.
AndreyT
Agreed, destructor needs to be called before placement new.
Alexander Gessler
@Andrey: It is then legal to completely destruct an object than re-use it's memory?
GMan
if the destructor does nothing you rely on, C++ explicitly allows you to omit calling it before creating a new object. but it doesn't hurt to call it. In the "worst" case, it's implicitly declared and the compiler will optimize out the call. In the best case, the destructor will free memory that's still occupied. But in fact, assignment is the way to go, i think.
Johannes Schaub - litb
@GMan: Well, yes. However, when the memory is static or automatic and the object has non-trivial destructor, then the type of the new object must be the same as the type of the old one. Otherwise, the behavior is undefined. Even just adding `const` leads to undefined behavior. It is all covered in 3.8.
AndreyT
@litb: I knew you secretly watch over everything and chime in randomly. :P And you mean if it's a trivial destructor? @AndreyT: Ah, thanks.
GMan
@GMan, the destructor can contain arbitrary code, it needs not be trivial. For example this is valid code: `struct A { A() { cout << "begin"; } ~A() { cout << "end"; } }; int main() { A a; new ((void*) }` as per 3.8/4: "For an object of a class type with a non-trivial destructor, the program is not required to call the destructor explicitly before the storage which the object occupies is reused or released; however, [...] any program that depends on the side effects produced by the destructor has undefined behavior."
Johannes Schaub - litb
@litb: Thanks, I see. I just find it weird you could potentially skip the destruction of an object safely :o
GMan
+6  A: 

Literally? Yes, by using placement new. But first you have to destruct the previously constructed object.

SomeClass object(1, 2, 3);
...
object.~SomeClass(); // destruct
new(&object) SomeClass(4, 5, 6); // reconstruct
...
// Final destruction will be done implicitly

The value of this does not go beyond purely theoretical though. Don't do it in practice. The whole thing is ugly beyond description.

AndreyT
+1  A: 

May-be not what you have in mind, but since you didn't mention what it is for, I suppose one answer would be that you'd do it by controlling scope and program flow.

For example, you wouldn't write a game like this:

initialize player
code for level 1
...
reinitialize player
code for level 2
...
etc

Instead you'd strive for:

void play_level(level_number, level_data) {
    Player player; //gets "re-initialized" at the beginning of each level using constructor
    //code for level
}

void game() {
    level_number = 1;
    while (some_condition) {
        play_level(level_number, level_data);
        ++level_number;
    }
 }

(Very rough outline to convey the idea, not meant to be remotely compilable.)

UncleBens
+3  A: 

Yes you can cheat and use placement new.
Note: I do not advice this:

#include <new>

reInitAnA(A& value)
{
    value.~A();            // destroy the old one first.
    new (&value) A();      // Call the constructor 
                           // uses placement new to construct the new object
                           // in the old values location.
}
Martin York
what if the new fails?
Jagannath
In this case new can't fail (in terms of memory allocation) as no memory is allocated. The constructor can fail and throw exceptions just like you would expect.
Martin York
Possibly what Jagannath means is, what if an exception is thrown, and the object passed as parameter is e.g. an automatic variable belonging to the caller, or a dynamically allocated object held by a smart pointer. When is it valid to call the destructor twice, how does one go about writing code to ensure validity, etc?
Steve Jessop
+1  A: 

Instead of destructing and reinitializing as suggested by some of the answers above, it's better to do an assignment like below. The code below is exception safe.

    T& reinitialize(int x, int y)
    {
        T other(x, y);
        Swap(other); // this can't throw.
        return *this;
    }
Jagannath