Гарантируется ли, что деструктор C++ не будет вызываться до конца блока?

в коде C++ ниже я гарантирую, что деструктор ~obj () будет называться после выполняется код / / More? Или компилятору разрешено уничтожать объект obj раньше, если он обнаруживает, что он не используется?

{
  SomeObject obj;
  ... // More code
}

Я хотел бы использовать этот метод, чтобы спасти меня от необходимости помнить, чтобы сбросить флаг в конце блока, но мне нужно, чтобы флаг оставался установленным для всего блока.

8 ответов


вы в порядке с этим - это очень часто используемый шаблон в программировании на C++. Из стандартного раздела C++ 12.4 / 10, ссылаясь на то, когда деструктор вызывается:

для построенного объекта с автоматическая длительность хранения когда блок, в котором находится объект созданные выходы


на самом деле...

C++ имеет что-то, называемое принципом "как будто". Все гарантии, на которые ссылаются во всех этих ответах, относятся только к наблюдаемых поведение. Компилятору позволено ellude, перестановка, добавление и т. д.. любой вызов функции, если наблюдаемое поведение таково, как если бы оно было выполнено, как первоначально написано. Это также относится к деструкторам.

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

более вероятно, что компилятор использует эту власть, чтобы сделать что-то полезное, как полностью ellude тривиальный деструктор однако вместо того, чтобы переупорядочивать вызовы деструктора.

Edit: кто-то хотел ссылку... 1.9 / 5, а также сноска 4 проекта стандарта C++0x (это не новое правило,у меня просто нет стандарта C++03. Он также присутствует в стандарте C, AFAIK)

1.9/5:

соответствующая реализация, выполняющая хорошо сформированную программу, должна производить такое же наблюдаемое поведение в качестве одной из возможных последовательностей выполнения соответствующий экземпляр абстрактной машины с та же программа и тот же вход. Однако, если такая последовательность выполнения содержит неопределенную операцию, этот международный стандарт не накладывает никаких требований на реализацию выполнения программы с ввод (даже в отношении операций, предшествующих первой неопределенной операции).

сноска 4:

Это положение иногда называют правилом "как если бы", потому что реализация может игнорировать любое требование этого Международный стандарт до тех пор, пока результат будет таким, как если бы требование было соблюдено, насколько это можно определить из наблюдаемое поведение программы. Например, фактическая реализация не должна оценивать часть выражения, если она может выведите, что его значение не используется и что никаких побочных эффектов, влияющих на наблюдаемое поведение программы, не производится.

мое чтение (и то, что я думал, было общим пониманием) было то, что это то, что позволяет компилятору делать все, что он хочет (т. е. позволяет оптимизировать), пока наблюдаемое поведение является поведением исходного письменного источника, включая перемещение деструкторов, не разрушая объекты вообще, изобретая деструкторы и т. д.


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

на C++ faq lite имеет хороший раздел о dtors


Destruction в C++ является детерминированным-это означает, что компилятор не может свободно перемещать этот код. (Конечно, оптимизация может встроить деструктор, определить, что код деструктора не взаимодействует с // More code и выполните некоторые переупорядочивания инструкций, но это еще одна проблема)

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

{
    LockClass lock(lockData);
    // More code
} // Lock automatically released.

кроме того, вы можете зависеть от деструкторов, работающих в обратном порядке от того, как были построены объекты.


Да, это гарантировано.

срок службы объекта с автоматической продолжительностью хранения заканчивается в конце его возможности и не раньше. Для такого объекта потенциальный охват начинается в точке объявления и заканчивается в конце блока, в котором она объявлена. Это момент, когда деструктор будет вызван.

обратите внимание, что очень педантично говоря, даже для автоматического объекта неправильно говорить, что он уничтожается, когда он "выходит за рамки" (в отличие от "выходит из своего потенциал scope"). Объект может выходить из области и возвращаться в область много раз (если в блоке объявлено еще больше локальных объектов с тем же именем), и выход из области таким образом не вызывает разрушения объекта. Это" самый последний конец " его области, который убивает автоматический объект, который определяется как конец его возможности как описано выше.

In фактически, языковой стандарт даже не опирается на понятие объем для описания времени жизни автоматических объектов (нет необходимости иметь дело со всеми этими терминологическими тонкостями). Он просто говорит, что объект уничтожается при выходе из блока, в котором он определен:)


да, стандарт C++ имеет очень специфические требования о том, когда объекты уничтожаются (в §12.4/10), и в этом случае он не должен быть уничтожен до тех пор, пока не завершится выполнение всего другого кода в блоке.


все ответы здесь касаются того, что происходит с именованными объектами, но для полноты вы, вероятно, должны знать правило для временных/анонимных объектов. (например,f(SomeObjectConstructor() или f(someFunctionThatReturnsAnObject()))

временные объекты уничтожаются как последний шаг в оценке полного выражения (1.9), которое (лексически) содержит точку, в которой они были созданы. Это верно, даже если эта оценка заканчивается исключение. (12.2 / 3 из ISO C++98 стандарт)

что в основном означает, что временно сгенерированные объекты сохраняются до следующего оператора. Два исключения относятся к временным, созданным как часть списка инициализации объекта (в этом случае временное уничтожается только после того, как объект полностью построен), и если ссылка сделана на временное (например,const Foo& ref = someFunctionThatReturnsAnobject()) (в этом случае время жизни объекта является временем жизни ссылки).


типичный пример этого, так же как ваш вопрос-boost::scoped_ptr (или аналогичный std:: auto_ptr):

{
    boost::scoped_ptr< MyClass > pMyClass( new MyClass );

    // code using pMyClass here

} // destruction of MyClass and memory freed