result_t work(resource_t& resource) {
lock_t ___(resource);
return work_impl(resource);
}
Гарантируется ли, что деструктор ___
будет называться ПОСЛЕ work_impl()
вернулся? Или компилятор может уничтожить ___
перед звонком work_impl()
?
выражение work_impl(resource)
будет выполнен, результат будет скопирован на сторону вызывающего или использован как временный. Затем объект ___
будет разрушен.
С другой стороны, не используйте __
или же ___
в качестве префикса любого идентификатора. Они зарезервированы для компилятора.
Если деструктор нетривиален, его нельзя назвать
преждевременно, при условии, что остальная часть кода верна. В
случай неопределенного поведения (скажем, имя переменной с двумя или
более смежный _
), конечно, нет никаких гарантий.
Компилятор может делать все, что ему нравится, если нет способа определить разницу. Но если деструктор имеет какой-то программно-видимый эффект, он всегда будет происходить ПОСЛЕ work_impl
возвращается.
Поведение этой программы на самом деле не определено, идентификатор __
является зарезервированный и мы можем видеть из проекта стандарта C ++ 17.6.4.3
Зарезервированные имена параграф 2 говорит:
Если программа объявляет или определяет имя в контексте, где оно зарезервировано, за исключением случаев, явно разрешенных этим разделом, ее поведение не определено.
и если мы посмотрим дальше в раздел 17.6.4.3.2
Глобальные имена который говорит:
Каждое имя, которое содержит двойное подчеркивание _ _ или начинается с подчеркивания, за которым следует заглавная буква (2.12), зарезервировано для реализации для любого использования.
так что, если компилятор не документирует __
свободен для использования кодом пользователя, то это зарезервированный.
Деструкторы вызываются неявно
Так что, если эта программа не вызывает неопределенное поведение правила для деструкторов, которые вызывается неявно можно взять из раздела проекта стандарта 12.4
Destructotrs параграф 11 который говорит (акцент мой)
— для построенных объектов со статической продолжительностью хранения (3.7.1) при завершении программы (3.6.3),
— для построенных объектов с продолжительностью хранения потока (3.7.2) на выходе из потока,
— для построенных объектов с автоматической продолжительностью хранения (3.7.3) при выходе из блока, в котором создан объект (6.7),
— для построенных временных объектов, когда заканчивается срок службы временного объекта (12.2),
так что это означает, что деструктор для автоматического объекта будет вызываться при выходе work()
, что должно произойти после того, как результаты будут возвращены. Мы можем видеть далее, что порядок объекты уничтожены в это также указано от 6.6
Операторы Jump:
При выходе из области (хотя и выполненной) объекты с автоматической продолжительностью хранения (3.7.3), которые были созданы в этой области, уничтожаются в порядке, обратном их построению. [Примечание: для временных данных см. 12.2. —Конечная записка]
Обратите внимание, что имена, которые содержат двойное подчеркивание __
или начните с символа подчеркивания, за которым следует заглавная буква защищены в любом объеме.