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

Является ли деструктор С++ гарантированно не вызываться до конца блока?

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

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

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

4b9b3361

Ответ 1

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

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

Ответ 2

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

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

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

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

Изменить: Кому-то нужна ссылка... 1.9/5, а также примечание 4 стандарта проекта С++ 0x (это не новое правило, у меня просто нет стандартный С++ 03, он также присутствует в стандарте C, AFAIK)

1,9/5:

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

Сноска 4:

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

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

Ответ 3

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

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

Ответ 4

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

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

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

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

Ответ 5

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

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

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

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

Ответ 6

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

Ответ 7

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

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

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

Ответ 8

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

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

    // code using pMyClass here

} // destruction of MyClass and memory freed