Spec-Zone.ru › Ada 2012
Справочник по Ada 2012

7.6 Присваивание и финализация

Три типа действий являются фундаментальными для работы с объектами: инициализация, финализация и присваивание. Каждый объект инициализируется, явным или по умолчанию, после создания (например, с помощью object_declaration или allocator). Каждый объект финализируется перед уничтожением (например, при выходе из subprogram_body, содержащего object_declaration, или при вызове Unchecked_Deallocation). Операция присваивания используется в assignment_statement, явной инициализации, передаче параметров и других операциях.
Язык предоставляет определения по умолчанию для этих трёх фундаментальных операций, но управляемый тип даёт пользователю дополнительный контроль над частями этих операций. В частности, пользователь может определить для управляемого типа процедуру Initialize, которая вызывается сразу после обычной инициализации по умолчанию управляемого объекта, процедуру Finalize, которая вызывается непосредственно перед финализацией любого из компонентов управляемого объекта, и процедуру Adjust, которая вызывается в последнюю очередь при присваивании (неограниченному) управляемому объекту.

Статическая семантика

Существует следующий определённый языком пакет библиотеки:
package Ada.Finalization is
pragma Pure(Finalization);
type Controlled is abstract tagged private;
pragma Preelaborable_Initialization(Controlled);
procedure Initialize (Object : in out Controlled) is null;
procedure Adjust (Object : in out Controlled) is null;
procedure Finalize (Object : in out Controlled) is null;
type Limited_Controlled is abstract tagged limited private;
pragma Preelaborable_Initialization(Limited_Controlled);
procedure Initialize (Object : in out Limited_Controlled) is null;
procedure Finalize (Object : in out Limited_Controlled) is null;
private
... -- не определено языком
end Ada.Finalization;
Управляемый тип является потомком Controlled или Limited_Controlled. Предопределённый оператор "=" типа Controlled всегда возвращает True, так как этот оператор включён в реализацию предопределённого оператора равенства для типов, полученных из Controlled, как объяснено в 4.5.2. Тип Limited_Controlled похож на Controlled, за исключением того, что он ограничен и не имеет примитивной подпрограммы Adjust.
Говорят, что тип требует финализации, если:
  • это управляемый тип, тип задачи или тип защищённого объекта; или
  • он имеет компонент, тип которого требует финализации; или
  • это тип всего класса; или
  • это частичный вид, полный вид которого требует финализации; или
  • это один из нескольких определённых языком типов, которые явно определены как требующие финализации.

Динамическая семантика

Во время разработки или вычисления конструкции, которая приводит к инициализации объекта по умолчанию, для каждого управляемого подкомпонента объекта, которому не присвоено начальное значение (как определено в 3.3.1), вызывается Initialize для этого подкомпонента. Аналогично, если объект, который инициализируется по умолчанию в целом, является управляемым, Initialize вызывается для объекта.
Для extension_aggregate, предком которого является ancestor_part — subtype_mark, обозначающий управляемый подтип, вызывается процедура Initialize родительского типа, если эта процедура не абстрактна.
Инициализация и другие операции инициализации выполняются в произвольном порядке, за исключением следующих случаев. Initialize применяется к объекту после инициализации его подкомпонентов, если таковые имеются (включая как неявную инициализацию, так и вызовы Initialize). Если объект имеет компонент с дискриминантом доступа, ограниченным выражением для каждого объекта, Initialize применяется к этому компоненту после любых компонентов, не имеющих таких дискриминантов. Для объекта с несколькими компонентами с таким дискриминантом, Initialize применяется к ним в порядке их component_declarationов. Для allocator любые активации задач следуют после всех вызовов Initialize.
При присваивании целевому объекту со всеми управляемыми частями значения, либо при его создании, либо в последующей assignment_statement, операция присваивания выполняется следующим образом:
  • Значение целевого объекта становится присвоенным значением.
  • Значение целевого объекта корректируется.
Для корректировки значения составного объекта значения компонентов объекта сначала корректируются в произвольном порядке, а затем, если объект является неуправляемым, вызывается Adjust. Корректировка значения элементарного объекта не оказывает никакого влияния, так же как и корректировка значения составного объекта без управляемых частей.
Для assignment_statement, после вычисления name и expression и выполнения любых преобразований (включая проверку ограничений), создаётся анонимный объект, и значение присваивается ему; то есть, применяется операция присваивания. (Присваивание включает корректировку значения). Затем целевой объект assignment_statement финализируется. Затем значение анонимного объекта присваивается целевому объекту assignment_statement. Наконец, анонимный объект финализируется. Как объясняется ниже, реализация может устранить промежуточный анонимный объект, поэтому это описание включает в себя то, что указано в 5.2, «Операторы присваивания».
Когда для инициализации объекта используется вызов функции или aggregate, результатом вызова функции или aggregate является анонимный объект, который присваивается новосозданному объекту. При таком присваивании анонимный объект может быть создан на месте, в этом случае присваивание не подразумевает копирования. В определённых случаях анонимный объект должен быть создан на месте. В частности:
  • Если полный тип любой части объекта неизменно ограничен, анонимный объект создаётся на месте.
  • В случае aggregate, если полный тип любой части вновь созданного объекта управляется, анонимный объект создаётся на месте.
  • В других случаях неявно, создаётся ли анонимный объект на месте.
Несмотря на то, что этот международный стандарт говорит об ином, если объект создаётся на месте:
  • После успешного завершения оператора возврата или aggregate, анонимный объект превращается в вновь созданный объект; то есть, анонимный объект перестаёт существовать, и вместо него появляется вновь созданный объект.
  • Финализация не выполняется для анонимного объекта.
  • Корректировка не выполняется для вновь созданного объекта.
  • Все значения доступа, которые обозначают части анонимного объекта, теперь обозначают соответствующие части вновь созданного объекта.
  • Все переименования частей анонимного объекта теперь обозначают представления соответствующих частей вновь созданного объекта.
  • Совмещения анонимного объекта становятся совпадениями вновь созданного объекта.

Разрешения реализации

Реализация имеет право смягчить вышеуказанные правила для assignment_statement следующим образом:
  • Если объекту присваивается значение этого же объекта, реализации не нужно ничего делать.
  • Для присваивания типа, не являющегося управляемым, реализация может финализировать и присваивать каждый компонент переменной по отдельности (а не финализировать всю переменную и присваивать всё новое значение), если дискриминант переменной не изменяется при присваивании.
  • Реализации не нужно создавать анонимный объект, если присваиваемое значение является результатом вычисления name, обозначающего объект (исходный объект), хранилище которого не может перекрываться с целевым. Если исходный объект может перекрываться с целевым объектом, реализация может избежать необходимости в промежуточном анонимном объекте, используя одно из вышеперечисленных разрешений, и выполнить присваивание по одному компоненту за раз (для присваивания перекрывающегося массива) или не выполнять вообще (для присваивания, где целевой и исходный объекты присваивания являются одним и тем же объектом).
Кроме того, реализация имеет право опустить неявные вызовы Initialize, Adjust и Finalize и связанные с ними операции присваивания для объекта неуправляемого типа при условии, что:
  • любой опущенный вызов Initialize не является вызовом определяемой пользователем процедуры Initialize, и
  • любое использование значения объекта после неявного вызова Initialize или Adjust и перед последующим вызовом Finalize для объекта не изменяет внешнего эффекта программы, и
  • после пропуска таких вызовов и операций, любое выполнение программы, которое выполняет вызов Initialize или Adjust для объекта или инициализирует объект с помощью агрегата, также позже выполнит вызов Finalize для объекта и всегда выполнит его перед присвоением нового значения объекту, и
  • операции присвоения, связанные с пропущенными вызовами Adjust, также пропускаются.
Это разрешение распространяется на вызовы Adjust и Finalize, даже если неявные вызовы имеют дополнительные внешние эффекты.


Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API