Подтвердить что ты не робот

Вызов конструктора для повторной инициализации объекта

Можно ли повторно инициализировать объект класса с помощью его конструктора?

4b9b3361

Ответ 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