Автоматическое уничтожение объекта

Гарантировано ли выполнение уничтожения автоматических объектов (объектов, созданных в стеке) не раньше, когда они выйдут за пределы области видимости?

Чтобы уточнить:

#include <iostream>

class A {
  public:
    A() {
      std::cout << "1";
    }
    ~A() {
      std::cout << "3";
    }
};

void test123() {
  A a;
  std::cout << "2";
}

Чтобы напечатать "2", a больше не требуется, поэтому теоретически компилятор может попытаться оптимизировать и уничтожить a, как только он больше не нужен.

Могу ли я полагаться на указанную выше функцию, всегда печатающую 123?


person bitmask    schedule 28.08.2011    source источник
comment
Из этого вопроса я понимаю, что вы исходите из сбора мусора. В .NET, например, такое поведение не гарантировано; сборщик мусора может завершить a в любое время после последней ссылки, которая в данном случае будет следующей строкой. Однако в C++, как упоминалось ниже, это строго определено.   -  person Mike Caron    schedule 29.08.2011
comment
Вы совершенно неправильно догадались :) --- Я просто использую это для реализации повторяющегося шаблона модуля.   -  person bitmask    schedule 29.08.2011
comment
Эх, попробовать стоило :)   -  person Mike Caron    schedule 29.08.2011


Ответы (3)


Порядок уничтожения объектов стека строго определен - они выполняются в порядке, обратном объявлению, когда вы покидаете область видимости (либо при выходе за конец {}, либо при return, либо по исключению). Таким образом, вы всегда будете видеть там 123.

Обратите внимание, однако, что оптимизация компилятора регулируется правилом «как если бы». Другими словами, компилятор может уничтожить объект раньше, пока полученная программа ведет себя так, как если бы она была уничтожена в обычное время. В этом случае, поскольку вы делаете вывод, компилятор должен запланировать вывод в нужное время. Однако если у вас есть, например, deleted указатель на примитивный тип, и компилятор может доказать, что нет других незавершенных указателей на это значение, он, в принципе, может переместить этот delete раньше. Суть в том, что никакая соответствующая программа не способна заметить эту оптимизацию.

person bdonlan    schedule 28.08.2011
comment
Это звучит неплохо. В реальном случае это не просто std::cout, но и серьезные побочные эффекты - множество вызовов функций и модификаций структуры данных перед уничтожением объекта. Все сломалось бы, если бы компилятор сначала уничтожил объект, даже если он нигде не используется в функции. Итак, согласно вашему объяснению, я в безопасности, верно? - person bitmask; 29.08.2011
comment
@bitmask, да, компилятор выполнит деструктор таким образом, что он фактически запускается в конце области. Выполнение побочных эффектов очистки в деструкторе считается хорошим стилем (часто называемым стилем RAII). - person bdonlan; 29.08.2011
comment
Спасибо за подтверждение :) - person bitmask; 29.08.2011

Стандарт определяет, что правильным поведением для этого кода является печать «123». Компиляторам разрешено изменять код столько, сколько они хотят, сохраняя ту же семантику (правило как если бы), и изменение порядка кода здесь изменит семантику, поэтому совместимый компилятор не может сделай это.

person David Rodríguez - dribeas    schedule 28.08.2011

Конструкторы могут иметь побочные эффекты. Например, они могут реализовать мьютекс, т.е. конструктор блокирует, а десктуктор разблокирует мьютекс. Поэтому 123 требуется.

person Ed Heal    schedule 28.08.2011