is it possible to re-initialize an object of a class using its constructor?
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.
a
was instantiated using a new
keyword? –
Roband use of deleted function
error. –
Frothy 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. –
Rectilinear 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.
clear
method separate from a constructor and destructor. –
Suchta 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. –
Onestep SomeClass
's constructor throws an exception, then the destructor is still called twice when it should be called only once, isn't it? –
Sufi 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);
cl->~CLASS();
prior to placement new, as I said on Jared's answer. I'm not sure if that's defined, seems legal. –
Bergen const
leads to undefined behavior. It is all covered in 3.8. –
Bran 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." –
Commemorate 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.
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.
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.) –
Bergen 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...
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.
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.
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.
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.)
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;
}
other
??? –
Lefkowitz 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
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;
}
© 2022 - 2024 — McMap. All rights reserved.