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

Уничтожьте и затем создайте новый объект, используя одну и ту же переменную

Иногда приятно начинать заново. В С++ я могу использовать следующий простой маневр:

{

    T x(31, Blue, false);

    x.~T();                        // enough with the old x

    ::new (&x) T(22, Brown, true); // in with the new!

    // ...
}

В конце области действия деструктор снова запустится, и все будет хорошо. (Пусть также говорят, что T немного особенный и ему не нравится назначаться, не говоря уже об обмене.) Но что-то говорит мне, что это не всегда без риска уничтожить все и повторить попытку. Существует ли возможный улов с этим подходом?

4b9b3361

Ответ 1

Я думаю, что единственный способ сделать это действительно безопасным для использования - потребовать, чтобы вызываемый конструктор был noexcept, например, добавив static_assert:

static_assert(noexcept(T(22, Brown, true)), "The constructor must be noexcept for inplace reconstruction");
T x(31, Blue, false);
x.~T();
::new (&x) T(22, Brown, true);

Конечно, это будет работать только для С++ 11.

Ответ 2

Если конструктор T выбрасывает вторую конструкцию, возникает проблема. Если вам нравятся подходы грубой силы, проверьте это:

T x(31, Blue, false);
x.~T();
const volatile bool _ = true;
for(;_;){
  try{
    ::new (&x) T(22, Brown, true);
    break; // finally!
  }catch(...){
    continue; // until it works, dammit!
  }
}

Он даже обеспечивает надежную гарантию!


На более серьезной ноте, это похоже на наступление на наземную мишень, зная, что она исчезнет, ​​если вы переместите ногу...

И здесь существует способ преодоления undefined поведения двойного разрушения:

#include <cstdlib>

T x(31, Blue, false);
x.~T();
try{
  ::new (&x) T(22, Brown, true);
}catch(...){
  std::exit(1); // doesn't call destructors of automatic objects
}

Ответ 3

Если выражается выражение конструкции T, вы удваиваете уничтожение объекта, который является UB. Конечно, даже желание сделать это свидетельствует о неудаче проектирования.

Ответ 4

Я попытался скомпилировать его, но я только осмелился запустить его под отладчиком. Поэтому я взглянул на демонтаж моего старого компилятора (комментарии тоже являются компиляторами):

@1 sub nerve.cells, fa0h
@2 xor x, x     // bitch.
@3 mov out, x
@4 test out, out
@5 jne @1
@6 xor x, x     // just in case.
@7 sub money, 2BC   // dammit.
@8 mov %x, new.one
@8 cmp new.one, %x 
@9 jne @7   
...
@25 jmp @1      // sigh... 

Ответ 5

Ммм. Поскольку вы делаете все, что С++ обескураживает, я думаю, что все забывают о goto.

Обратите внимание, что после явного вызова X.~T() и до того, как он будет восстановлен 1 все равно будет двойное разрушение, если кто-то сделал goto до объявления/инициализации переменной x (даже внутри внутреннего блока видимости).

Поскольку вы, очевидно, можете просто документировать это, я не буду переживать, когда пытаюсь "исправить" это. Вы могли бы концептуально разработать класс RAII для управления реконструкцией объекта на месте, делая этот маневр безопасным для goto в любом месте. Обратите внимание, что вы могли бы получить, что вызов конструктора-компоновщика-места прекрасно переадресовывается из деструктора объекта менеджера RAII. Жизнь хороша.

Другие оговорки по-прежнему применяются, конечно (см. другие ответы)


1 мы можем предположить, что для этого момента не может быть построено

Ответ 6

Нет ничего, чтобы остановить вас, это будет работать в большинстве случаев. Но, как и в случае с большим количеством С++, знание особенностей ваших дел будет заключаться в различии между работой, которую вы хотите, и дампом ядра. Есть очень немного примеров причин, по которым я мог понять, почему вы хотели бы сделать это в реальной программе, единственной, которая имеет смысл, является файл с отображением памяти.