Справочник по Ada 2005
7.6.1 Завершение и финализация
В этом подпункте определяются завершение и выход из выполнения конструкций и сущностей. Главный процесс — это выполнение конструкции, включающей финализацию локальных объектов после завершения (и после ожидания любых локальных задач — см. 9.3), но перед выходом. Другие конструкции и сущности покидаются сразу после завершения.
Динамическая семантика
Выполнение конструкции или сущности считается завершенным, когда достигнут конец этого выполнения или когда передача управления (см. 5.1) приводит к его прекращению. Завершение из-за достижения конца выполнения или из-за передачи управления оператором exit_statement, оператором возврата, goto_statement или requeue_statement или выбора terminate_alternative называется нормальным завершением. Иначе завершение считается ненормальным — когда управление передаётся из конструкции из-за прерывания или поднятия исключения.
После завершения выполнения конструкции или сущности она покидается, что означает продолжение выполнения следующего действия, как определено для выполняемого действия. Выход из выполнения происходит сразу после его завершения, за исключением случаев главного процесса: выполнения тела, отличного от package_body; выполнения statement; или оценки expression, function_call или range, которые не являются частью охватывающего expression, function_call, range или simple_statement, кроме simple_return_statement. Главный процесс финализируется после завершения и перед выходом из него.
Для финализации главного процесса, сначала ожидают зависимые задачи, как описано в 9.3. Затем каждый объект, уровень доступа которого совпадает с уровнем доступа главного процесса, финализируется, если объект был успешно инициализирован и всё ещё существует. Эти действия выполняются независимо от того, покинул ли главный процесс выполнение, достигнув последней инструкции, или посредством передачи управления. Когда передача управления приводит к завершению выполнения, каждый включенный главный процесс финализируется в порядке от самого внутреннего к самому внешнему.
Для финализации объекта:
- Если объект является элементарного типа, финализация не имеет эффекта;
- Если объект является контролируемого типа, вызывается процедура Finalize;
- Если объект является типа защищённого типа, выполняются действия, определённые в 9.4;
- Если объект является составного типа, то после выполнения вышеперечисленных действий, если таковые имеются, каждый компонент объекта финализируется в произвольном порядке, за исключением следующих случаев: если объект имеет компонент с дискриминантом доступа, ограниченным выражением, относящимся к объекту, этот компонент финализируется перед компонентами, не имеющими таких дискриминантов; для объекта с несколькими компонентами с таким дискриминантом, они финализируются в обратном порядке их component_declarationов;
- Если объект имеет корасширения (см. 3.10.2), каждое корасширение финализируется после объекта, дискриминант доступа которого его обозначает.
Непосредственно перед тем, как экземпляр Unchecked_Deallocation освободит память объекта, объект финализируется. Если экземпляр Unchecked_Deallocation никогда не применяется к объекту, созданному allocatorом, объект всё ещё будет существовать при завершении соответствующего главного процесса, и он будет финализирован тогда.
Порядок, в котором финализация главного процесса выполняет финализацию объектов, следующий: объекты, созданные объявлениями в главном процессе, финализируются в обратном порядке их создания. Для объектов, которые были созданы allocatorами для типа доступа, чьим конечным предком является объявленный в главном процессе, это правило применяется, как если бы каждый такой объект, который всё ещё существует, был создан в произвольном порядке в первой точке заморозки (см. 13.14) конечного предка типа; финализация этих объектов называется финализацией коллекции. После завершения финализации главного процесса объекты, финализированные в рамках его финализации, перестают существовать, как и любые типы и подтипы, определенные и созданные внутри главного процесса.
Целевое значение assignment_statement финализируется перед копированием нового значения, как объяснено в 7.6.
Главным процессом объекта является главный процесс, содержащий его создание, уровень доступа которого (см. 3.10.2) равен уровню доступа объекта.
В случае expression, являющегося главным процессом, финализация любых (анонимных) объектов происходит как заключительная часть вычисления expression.
Ограниченные (временные) ошибки
Ошибка является ограниченной, если вызов Finalize или Adjust, который происходит в рамках финализации объекта или присваивания, распространяет исключение. Возможные последствия зависят от действия, вызвавшего операцию Finalize или Adjust:
- Для Finalize, вызванного в рамках assignment_statement, Program_Error поднимается в этот момент.
- Для Adjust, вызванного в рамках операций присваивания, отличных от операций, вызванных в рамках assignment_statement, другие запланированные корректировки могут быть или не быть выполнены, а затем поднимается Program_Error. Во время его распространения финализация может быть или не быть применена к объектам, у которых Adjust потерпел неудачу. Для Adjust, вызванного в рамках assignment_statement, любые другие корректировки, которые должны быть выполнены, выполняются, а затем поднимается Program_Error.
- Для Finalize, вызванного в рамках вызова экземпляра Unchecked_Deallocation, любые другие планируемые финализации выполняются, а затем поднимается Program_Error.
- Для Finalize, вызванного в рамках финализации анонимного объекта, созданного вызовом функции или aggregate, любые другие планируемые финализации выполняются, а затем поднимается Program_Error.
- Для Finalize, вызванного из-за достижения конца выполнения главного процесса, любые другие финализации, связанные с главным процессом, выполняются, и Program_Error поднимается сразу после выхода из главного процесса.
- Для Finalize, вызванного передачей управления оператором exit_statement, оператором возврата, goto_statement или requeue_statement, Program_Error поднимается не раньше, чем после финализации главного процесса, в котором возникло исключение, и не позже точки, в которой нормальное выполнение продолжилось бы. Любые другие запланированные финализации до этой точки выполняются перед поднятием Program_Error.
- Для Finalize, вызванного передачей управления из-за поднятия исключения, любые другие планируемые финализации для того же главного процесса выполняются; Program_Error поднимается сразу после выхода из главного процесса.
- Для Finalize, вызванного передачей управления из-за прерывания или выбора альтернативы завершения, исключение игнорируется; любые другие планируемые финализации выполняются.
ПРИМЕЧАНИЯ
17 Правила раздела 10 подразумевают, что непосредственно перед завершением разделов выполняются операции Finalize для объектов контролируемых типами на уровне библиотеки (включая те, что созданы allocatorами типов доступа на уровне библиотеки, за исключением тех, которые уже финализированы). Это происходит после ожидания завершения задач на уровне библиотеки.
18 Константа является константой только между её инициализацией и финализацией. Инициализация и финализация могут изменять значение константы.
19 Прерывание откладывается во время определённых операций, связанных с типами контролируемых типов, как объяснено в 9.8. Эти правила препятствуют тому, чтобы прерывание привело к тому, что управляемый объект останется в неопределённом состоянии.
20 Процедура Finalize вызывается при финализации объекта контролируемого типа, даже если Finalize был вызван ранее, явно или в рамках присваивания; следовательно, если контролируемый тип является видимым (что подразумевает, что его примитив Finalize непосредственно вызываем), или является нелимитированным (что подразумевает, что присваивание разрешено), его процедура Finalize должна быть спроектирована таким образом, чтобы не иметь отрицательного эффекта, если она применяется во второй раз к тому же объекту.