Можно ли повторно инициализировать объект класса с помощью его конструктора?
Вызов конструктора для повторной инициализации объекта
Ответ 1
Сорт. Учитывая класс A:
A a;
...
a = A();
последнее утверждение не является инициализацией, это назначение, но оно, вероятно, делает то, что вы хотите.
Ответ 2
Буквально? Да, используя новое место размещения. Но сначала вы должны уничтожить ранее построенный объект.
SomeClass object(1, 2, 3);
...
object.~SomeClass(); // destruct
new(&object) SomeClass(4, 5, 6); // reconstruct
...
// Final destruction will be done implicitly
Значение этого не выходит за рамки чисто теоретического. Не делайте этого на практике. Все это некрасиво выходит за рамки описания.
Ответ 3
Возможно, хотя это очень плохая идея. Причина в том, что без вызова деструкторов на существующий объект вы собираетесь утечка ресурсов.
С этим основным предостережением, если вы настаиваете на этом, вы можете использовать новое размещение.
// Construct the class
CLASS cl(args);
// And reconstruct it...
new (&cl) CLASS(args);
Ответ 4
Нет, конструкторы вызываются только при первом создании объекта. Вместо этого напишите новый метод.
Edit
Я не буду признавать размещение новым, потому что я не хочу, чтобы у меня был любитель-хищник.
Посмотрите этот комикс, но подумайте об этой теме...
Ответ 5
Короткий ответ:
Нет. Если часть вашего целевого поведения объекта должна быть инициализирована несколько раз, тогда лучший способ реализовать это - доступный метод инициализации. Конструктор вашего класса может просто отложить этот метод.
class C1 {
public:
C1(int p1, int p2) {
Init(p1,p2);
}
void Init(int p1, int p2) { ... }
};
Угол ниппеля:
Есть ли какой-то невероятно злой способ вызвать конструктор в С++ после создания объекта? Почти наверняка, это С++. Но это в корне зло, и это поведение почти наверняка не определено стандартом, и его следует избегать.
Ответ 6
В С++ 11 вы можете сделать это:
#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)...);
}
Это позволяет использовать Reconstruct
передачу произвольных параметров конструктора любому объекту. Это может избежать необходимости поддерживать кучу методов Clear
и ошибок, которые могут легко остаться незамеченными, если в какой-то момент объект изменится, а метод Clear
больше не соответствует конструктору.
Вышеприведенное будет работать отлично в большинстве контекстов, но неудачно, если ссылка связана с базой внутри производного объекта, который имеет виртуальный деструктор. По этой причине описанная выше реализация предотвращает использование объектов, имеющих виртуальный деструктор.
Ответ 7
Да, вы можете обмануть и использовать новое место. Примечание: я не советую:
#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.
}
Ответ 8
Я обычно пишу следующее в современном С++:
SomeClass a;
...
a = decltype(a)();
Это может быть не самый эффективный способ, поскольку он эффективно создает другой объект того же типа a
и присваивает его a
, но он работает в большинстве случаев, вам не нужно запоминать тип от a
, и он адаптируется, если тип изменяется.
Ответ 9
Может быть, это не то, что вы имеете в виду, но поскольку вы не указали, для чего это важно, я полагаю, что один ответ будет заключаться в том, что вы сделаете это, контролируя объем и поток программ.
Например, вы не будете писать такую игру:
initialize player
code for level 1
...
reinitialize player
code for level 2
...
etc
Вместо этого вы бы стремились:
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;
}
}
(Очень грубая схема, чтобы передать идею, а не быть удаленно компилируемой.)
Ответ 10
Вместо того, чтобы разрушать и повторять инициализацию, как предложено некоторыми из вышеперечисленных ответов, лучше выполнить задание, как показано ниже. Код ниже является безопасным для исключений.
T& reinitialize(int x, int y)
{
T other(x, y);
Swap(other); // this can't throw.
return *this;
}
Ответ 11
В то время как большинство ответов переинициализируют объект в два этапа; во-первых, создание исходного объекта, а затем создание другого объекта и замена его на первый с использованием placement new
; этот ответ охватывает случай, когда вы сначала создаете указатель на пустой объект, а затем выделяете и конструируете его:
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