94

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

cpx
  • 17,009
  • 20
  • 87
  • 142

13 Answers13

94

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.

  • 13
    +1 Of course this also requires writing a complete, correct assignment operator. – Greg Hewgill Jan 30 '10 at 01:08
  • 30
    @Greg This requires HAVING a correct assignment operator, not necessarily WRITING one - the default will often be perfectly OK. –  Jan 30 '10 at 09:44
  • 1
    Will this cause a resource leak if `a` was instantiated using a `new` keyword? – davidhood2 Nov 20 '16 at 20:31
  • 2
    @davidhood2 in this case you can't instantiate using the new keyword, then you would create A* instead of A. If you are assigning to A* though and you use new you should know where you are deleting this to avoid resource leaks. Instead of writing the delete yourself you are probablt safer using smart pointers. – turoni Apr 13 '17 at 11:52
  • Weirdly, when I do this I get a `use of deleted function` error. – Jacob Garby Jun 10 '18 at 17:49
  • Move assignment will be used if supported which reduces at least all the copying that might otherwise occur. – wcochran Jul 23 '20 at 21:25
  • @JacobGarby is there a reason both the copy assignment and move assignment operators are deleted? – wcochran Jul 23 '20 at 21:26
  • Is there a way to do this without knowing the type of `a`? To give an example, if `class B : public A`, then I would want to have `A a = B();` and then later reconstruct variable `a` with `B`, but without knowing that it's `B` specifically. – Aaron Franke Sep 17 '22 at 23:26
67

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.

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
  • 19
    Can you explain why you believe this is "ugly beyond description"? It seems to me it has a legitimate use in avoiding code duplication and bugs arising from having a `clear` method separate from a constructor and destructor. – denis bider May 26 '15 at 13:04
  • 6
    What makes this "ugly" is that after calling the destructor on `object`, you have an uninitialized stack variable. Trying to do anything with `object` after this point is unsafe. There's not even a way to detect that the object has been destructed later. But once reconstructed, it's valid again. I would say as long as those two lines are back-to-back, this is safe. – Eric Hein Oct 27 '16 at 14:54
  • 2
    Honestly, I'd probably put this in some kind of vardic template function or even just a macro, to make it clear what's happening and to prevent code being accidentally inserted between the two statements. – NotVeryMoe Nov 24 '16 at 17:11
  • 3
    Incredibly useful to me, since I'm working on implementing a memory pool... Thanks! I agree, though... unless you're taking responsibility for how allocation and deallocation are handled, this is Really Bad Idea. :) – Kevin Dill Aug 29 '17 at 20:41
  • Well, this is the exact answer for the original question. – Géza Török Dec 13 '17 at 23:03
  • Ugly or not, this is a very good solution for re-initialization in static memory applications. – Jordan Oct 01 '18 at 22:04
  • Can you please explain your comment *Final destruction will be done implicitly* ? – JFMR Jun 18 '19 at 13:32
  • 1
    @ElProfesor In my example the object is declared locally (or statically), which means that as usual the compiler will perform its destruction at the end of the object's lifetime. I.e. the compiler will automatically/implicitly destruct it. – AnT stands with Russia Jun 18 '19 at 14:40
  • 1
    @AnT Thanks for your explanation, I understand now. If the 2nd call to `SomeClass`'s constructor throws an exception, then the destructor is still called twice when it should be called only once, isn't it? – JFMR Jun 18 '19 at 15:38
  • Is it necessary to call the destructor first? – Gill Bates Aug 09 '20 at 21:20
  • 1
    @Gill Bates: In general case: yes. In some specific cases it is optional. – AnT stands with Russia Aug 10 '20 at 16:52
28

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
  • 74,869
  • 16
  • 134
  • 187
  • 6
    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 Jan 30 '10 at 00:03
  • 10
    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. – GManNickG Jan 30 '10 at 00:04
  • 2
    +1, only right solution. Nothing evil, it's the way how it's done. – Alexander Gessler Jan 30 '10 at 00:05
  • 4
    @Alexander: As the answer stands, it's evil and undefined. – GManNickG Jan 30 '10 at 00:06
  • 10
    No, the solution is not correct. It is critical to remember to destruct the "old" object first. – AnT stands with Russia Jan 30 '10 at 00:06
  • 1
    Agreed, destructor needs to be called before placement new. – Alexander Gessler Jan 30 '10 at 00:07
  • @Andrey: It is then legal to completely destruct an object than re-use it's memory? – GManNickG Jan 30 '10 at 00:11
  • 3
    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 Jan 30 '10 at 00:18
  • 1
    @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. – AnT stands with Russia Jan 30 '10 at 00:20
  • @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. – GManNickG Jan 30 '10 at 00:21
  • @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*)&a) A; }` 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 Jan 30 '10 at 00:32
  • @litb: Thanks, I see. I just find it weird you could potentially skip the destruction of an object safely :o – GManNickG Jan 30 '10 at 00:41
17

In C++11, you can do this:

#include <type_traits>

template <class T, typename... Args>
void Reconstruct(T& x, Args&&... args)
{
    static_assert(!std::has_virtual_destructor<T>::value, "Unsafe"); 
    x.~T();
    new (&x) T(std::forward<Args>(args)...);
}

This allows you to use Reconstruct passing arbitrary constructor parameters to any object. This can avoid having to maintain a bunch of Clear methods, and bugs that can easily go unnoticed if at some point the object changes, and the Clear method no longer matches the constructor.

The above will work fine in most contexts, but fail horribly if the reference is to a base within a derived object that has a virtual destructor. For this reason, the above implementation prevents use with objects that have a virtual destructor.

denis bider
  • 434
  • 3
  • 8
13

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
  • 733,204
  • 149
  • 1,241
  • 1,454
  • 2
    You could do: `T x; x->~T(); new (&x) T();` 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.) – GManNickG Jan 30 '10 at 00:01
  • Have you read the standard? Is placement new really not defined by it, or are you just assuming that because it seems foreign to you...? – Kröw Aug 18 '23 at 03:01
10

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
  • 41,220
  • 11
  • 99
  • 130
9

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.
}

Personally I would go with constructing a new one. Then move the new object "onto" the old one:

#include <new>

reInitAnA(A& value)
{
    value = A{};     // Construct a temporary.
                     // Use assignment to move (or copy when no
                     // move is available).
                     //
                     // destructor of temp then called.
}

Or you could add a method that re-initializes the object. But that goes against your requirement of using the constructor.

Martin York
  • 257,169
  • 86
  • 333
  • 562
  • 1
    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 Jan 30 '10 at 01:57
  • 1
    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 Jan 30 '10 at 15:27
5

I usually write the following in modern C++ :

SomeClass a;
...
a = decltype(a)();

It may be not the most effective way, as it effectively constructs another object of the same type of a and assigns it to a, but it works in most cases, you don't have to remember the type of a, and it adapts if the type changes.

Coyl
  • 51
  • 1
  • 2
2

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
  • 40,819
  • 6
  • 57
  • 90
2

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
  • 3,995
  • 26
  • 30
2

If you really must do this I strongly encourage creating a reset method for this:

class A
{
 ...
  public:
    reset() { *this= A() };
}

The above requires A to be copy and move assignable. That is because the initial unoptimized version will copy from a temp. However copy elision may remove this step.

The behavior of A::reset() is always well defined. It replace the existing data in a valid A instance with a data from a new one. Of course any sub-class of A will still need to define its own version if you wanted its data re-initialized as well. However, failure to do so does not in and of itself invoke undefined or unspecified behavior. It simply means that only whatever memory A uses for its members will be reset. Even the involvement of virtual functions and/or virtual inheritance doesn't change this. Although the usual caveats of using such things apply.

Raw pointers will not be deleted by the above so they will need to be put into a std::shared_ptr or similar construct so the will self destruct when no longer needed.

0

While most answers are reinitializing an object in two steps; first, creating an initial object, and second creating another object and swapping it with the first one using placement new, this answer covers the case that you first create a pointer to an empty object and later allocate and construct it:

class c *c_instance; // Pointer to class c
c_instance = new c(arg1, ..., argn) // Allocate memory & call the proper constructor 
// Use the instance e.g. c->data
delete c_instance; // Deallocate memory & call the destructor 
hmofrad
  • 1,784
  • 2
  • 22
  • 28
0

Yes , it is possible. If you create a method that returns a new object.

#include "iostream"
class a // initialize class
a getNewA(a object){// Create function to return new a object
a new_object(/*Enter parameters for constructor method*/);
return new_object;
}
Ethan Eyob
  • 19
  • 4