Справочник Ada (Ada 2022)
3.10.2 Операции типов доступа
Атрибут Access используется для создания значений доступа, обозначающих объекты с алиасами и не-встроенные подпрограммы. Правила «доступности» предотвращают висячие ссылки (в отсутствие использования определённых функций unchecked — см. главу 13).
Правила разрешения имён
Для attribute_reference с attribute_designator Access (или Unchecked_Access — см. 13.10) ожидаемый тип должен быть единственным типом доступа A, таким что:
- A — тип доступа к объекту с обозначаемым типом D, и тип prefix — D'Class или подтип D;
- A — тип доступа к подпрограмме, чья обозначаемая сигнатура совместима по типу с prefix.
prefix такого attribute_reference никогда не интерпретируется как implicit_dereference или безаргументный function_call (см. 4.1.4). Обозначаемый тип или сигнатура ожидаемого типа attribute_reference — ожидаемый тип или сигнатура для prefix.
Статическая семантика
Правила доступности, предотвращающие висячие ссылки, выражены через уровни доступности, которые отражают временную вложенность мастеров. Как объяснено в 7.6.1, мастер — это выполнение определенного конструкта (называемого мастер-конструктом), например, subprogram_body. Уровень доступности глубее другого, если он более глубоко вложен во время выполнения. Например, объект, объявленный локально для вызываемой подпрограммы, имеет более глубокий уровень доступности, чем объект, объявленный локально для вызывающей подпрограммы. Правила доступности для типов доступа требуют, чтобы уровень доступности объекта, обозначаемого значением доступа, не был глубже уровня доступности типа доступа. Это гарантирует, что объект будет существовать как минимум так же долго, как и тип доступа, что в свою очередь гарантирует, что значение доступа не может позднее обозначать объект, который больше не существует. Атрибут Unchecked_Access может быть использован для обхода правил доступности.
Данный уровень доступности считается статически более глубоким, чем другой, если данный уровень известен во время компиляции (как определено ниже) как более глубокий, чем другой, для всех возможных выполнений. В большинстве случаев доступность обеспечивается на этапе компиляции правилами легальности. Также используются проверки доступности во время выполнения, так как правила легальности не покрывают определённые случаи, включающие параметры доступа и обобщённые пакеты.
Каждый мастер, и каждый созданный им сущность и вид, имеет уровень доступности; когда два уровня определены как одинаковые, уровни доступности двух связанных сущностей считаются связанными друг с другом. Уровни доступности определяются следующим образом:
- Уровень доступности данного мастера глубже уровня каждого динамически окружающего мастера и глубже уровня каждого мастера, от которого напрямую зависит задача, выполняющая данный мастер (см. 9.3).
- Сущность или вид, определённые объявлением и созданные в ходе его обработки, имеют тот же уровень доступности, что и самый внутренний мастер объявления, за исключением случаев переименования и производных типов доступа, описанных ниже. Формальный параметр вызываемой сущности имеет тот же уровень доступности, что и мастер, представляющий вызов сущности.
- Уровень доступности представления объекта или подпрограммы, определённого renaming_declaration, совпадает с уровнем доступности переименовываемого представления, за исключением случаев переименования формальной подпрограммы, в этом случае уровень доступности — уровень экземпляра.
- Уровень доступности преобразования вида, qualified_expression или скобочной выражения, совпадает с уровнем доступности операнда.
- Уровень доступности conditional_expression (см. 4.5.7) — уровень доступности оцениваемого dependent_expression.
- Уровень доступности declare_expression (см. 4.5.9) — уровень доступности body_expression.
- Уровень доступности aggregate, используемого (в полном объёме) для непосредственной инициализации части объекта, — уровень доступности инициируемого объекта. В других контекстах уровень доступности aggregate — уровень самого внутреннего мастера, оценивающего aggregate. Соответствующие правила применяются к преобразованию значений (см. 4.6).
- Уровень доступности результата вызова функции — уровень мастера вызова функции, определяемый точкой вызова следующим образом:
Если тип результата в точке объявления функции (или типа доступа к функции) — составной тип, и результат используется (в полном объёме) для непосредственной инициализации части объекта, то мастер — мастер инициируемого объекта. В случае, когда инициируемый объект является корасширением (см. ниже), которое становится корасширением другого объекта, то мастер — мастер конечного объекта, к которому будет перенесено корасширение.
Если результат имеет анонимный тип доступа и преобразуется в (именованный или анонимный) тип доступа, мастер определяется по правилам, приведённым ниже, для определения мастера объекта, созданного аллокатором (даже если результат доступа имеет тип доступа к подпрограмме);
Этот абзац был удалён.
Если сам вызов определяет результат функции F или имеет уровень доступности, связанный с результатом такой функции F, то мастер вызова — мастер вызова, вызвавшего F;
В других случаях мастер вызова — самый внутренний мастер, оценивающий вызов функции.
В случае вызова функции, тип результата которой — анонимный тип доступа, уровень доступности типа результата вызова функции также определяется точкой вызова, как описано выше.
- Внутри оператора return уровень доступности возвращаемого объекта — уровень выполнения оператора return. Если оператор return завершается нормально, возвращаясь из функции, то перед завершением функции уровень доступности возвращаемого объекта изменяется на уровень, определяемый точкой вызова, как и уровень любых корасширений (см. ниже) возвращаемого объекта.
- Уровень доступности производного типа доступа совпадает с уровнем его конечного предка.
- Уровень доступности анонимного типа доступа, определённого access_definition object_renaming_declaration, совпадает с уровнем доступности переименовываемого представления.
- Уровень доступности анонимного типа доступа, определённого access_definition loop_parameter_subtype_indication, — уровень параметра цикла.
- Уровень доступности анонимного типа доступа дискриминанты доступа в subtype_indication или qualified_expression allocator, или в expression или return_subtype_indication оператора return определяется следующим образом:
Если значение дискриминанты доступа определяется discriminant_association в subtype_indication, уровень доступности объекта или подпрограммы, обозначаемой связанным значением (или уровень библиотеки, если значение — null);
Если значение дискриминанты доступа определяется default_expression в объявлении дискриминанты, уровень доступности объекта или подпрограммы, обозначаемой связанным значением (или уровень библиотеки, если null);
Если значение дискриминанты доступа определяется record_component_association в aggregate, уровень доступности объекта или подпрограммы, обозначаемой связанным значением (или уровень библиотеки, если значение — null);
В других случаях, где значение дискриминанты доступа определяется объектом с неограниченным номинальным подтипом, — уровень доступности объекта.
- Уровень доступности анонимного типа доступа дискриминанты доступа в любом другом контексте — уровень окружающего объекта.
- Уровень доступности анонимного типа доступа параметра доступа, указывающего тип доступа к объекту, совпадает с уровнем представления, обозначаемого фактическим (или уровнем библиотеки, если фактический — null).
- Уровень доступности анонимного типа доступа параметра доступа, указывающего тип доступа к подпрограмме, глубже, чем у любого мастера; все такие анонимные типы доступа имеют этот же уровень.
- Уровень доступности анонимного подтипа доступа, определенного return_subtype_indication, который является access_definition (см. 6.5), соответствует уровню подтипа результата включающей функции.
- Уровень доступности типа автономного объекта анонимного типа доступа к объекту такой же, как уровень доступности типа значения доступа, последнее присвоенного объекту; проверки доступности гарантируют, что он никогда не будет глубже уровня объявления автономного объекта.
- Уровень доступности объекта, созданного allocator, такой же, как и уровня типа доступа, за исключением allocator анонимного типа доступа (анонимный allocator) в определенных контекстах, как следует: Для анонимного allocator, определяющего результат функции с результатом доступа, уровень доступности определяется так, как будто allocator находится на месте вызова функции; в специальном случае вызова, являющегося операндом преобразования типа, уровень соответствует целевому типу доступа преобразования. Для анонимного allocator, определяющего значение параметра доступа, уровень доступности соответствует самому внутреннему мастеру вызова. Для анонимного allocator, тип которого является типом автономного объекта анонимного типа доступа к объекту, уровень доступности соответствует уровню объявления автономного объекта. Для определяющего дискриминант доступа, уровень доступности определяется следующим образом:
для allocator, используемого для определения дискриминанта объекта, уровень объекта;
для allocator, используемого для определения ограничения в subtype_indication в любом другом контексте, уровень мастера, который обрабатывает subtype_indication.
Этот абзац был удалён.
В первом случае, выделенный объект считается корасширением объекта, дискриминант которого его обозначает, а также любого объекта, которого выделенный объект является корасширением или подкомпонентом. Если выделенный объект является корасширением анонимного объекта, представляющего результат агрегата или вызова функции, который используется (полностью) для непосредственной инициализации части объекта, после присвоения результата, корасширение становится корасширением инициируемого объекта и больше не считается корасширением анонимного объекта. Все корасширения объекта (которые не были переданы такой инициализацией) завершаются, когда объект завершается (см. 7.6.1).
- В операторе return уровень доступности анонимного типа доступа к результату доступа соответствует мастеру вызова.
- Уровень доступности представления объекта или подпрограммы, обозначенного значением доступа, такой же, как и уровень типа доступа.
- Уровень доступности компонента, защищенной подпрограммы или входа (представления) составного объекта такой же, как и уровня (представления) составного объекта.
В вышеуказанных правилах оперативные составляющие name или expression (см. 4.4) считаются используемыми в данном контексте, если включающая name или expression используется в этом контексте.
Один уровень доступности определяется как статически глубже другого в следующих случаях:
- Для мастер-конструкции, которая статически вложена в другую мастер-конструкцию, уровень доступности внутренней мастер-конструкции статически глубже, чем у внешней мастер-конструкции.
- Уровень доступности анонимного типа доступа параметра доступа, указывающего тип доступа к подпрограмме, статически глубже, чем у любого мастера; все такие анонимные типы доступа имеют этот же уровень.
- Отношение статически глубже не применяется к уровню доступности следующего:
анонимный тип параметра доступа, указывающего тип доступа к объекту;
тип автономного объекта анонимного типа доступа к объекту;
потомок формального типа обобщения;
потомок типа, объявленного в формальном пакете обобщения.
- Когда отношение статически глубже не применяется, уровень доступности не считается статически глубже или статически мельче любого другого.
- Этот абзац был удалён.
- Когда внутри тела функции или выражения возврата выражения функции, уровень доступности мастера, представляющего выполнение функции, статически глубже, чем у мастера вызова функции, вызывающего это выполнение, независимо от того, как определяется мастер вызова функции (см. выше).
- Для определения, является ли один уровень статически глубже другого при нахождении внутри тела обобщенного пакета, обобщенный пакет предполагается инстанцированным на том же уровне, что и при объявлении; требуются проверки во время выполнения в случае более глубоких вложенных инстанцирований.
- Для определения, является ли один уровень статически глубже другого при нахождении внутри области объявления type_declaration, текущий экземпляр типа предполагается объектом, созданным на более глубоком уровне, чем уровень типа.
Несмотря на другие правила, указанные выше, уровень доступности сущности, связанной с явным алиасом формального параметра включающей функции, считается (как статически, так и динамически) таким же, как и уровень сущности, уровень доступности которой связан с объектом-возвратом этой функции.
Уровень доступности всех единиц библиотек называется уровнем библиотеки; объявление или сущность уровня библиотеки — это то, чей уровень доступности — уровень библиотеки.
Следующий атрибут определен для prefix X, обозначающего алиасовое представление объекта:
X'Access
X'Access возвращает значение доступа, обозначающее объект, обозначаемый X. Тип X'Access — тип доступа к объекту, как определено ожидаемым типом. Ожидаемый тип должен быть общим типом доступа. X должен обозначать алиасовое представление объекта, включая, возможно, текущий экземпляр (см. 8.6) ограниченного типа в его определении, или формальный параметр или формальный обобщенный объект помеченного типа. Представление, обозначаемое префиксом X, должно удовлетворять следующим дополнительным требованиям, предполагая, что ожидаемый тип для X'Access — общий тип доступа A с типом назначения D:
Если A — тип доступа к переменной, то представление должно быть переменной; с другой стороны, если A — тип доступа к константе, представление может быть либо константой, либо переменной.
Представление не должно быть подкомпонентом, зависящим от дискриминантов объекта, если объект не известен как ограниченный.
Если A — именованный тип доступа, а D — помеченный тип, то тип представления должен покрываться D; если A — анонимный, а D — помеченный, то тип представления должен быть либо D'Class, либо типом, покрывающим D; если D — неопознанный, то тип представления должен быть D, и либо:
обозначенный подтип A должен статически совпадать с номинальным подтипом представления; или
D должен быть дискриминирован в полном представлении и не ограничен в любом частичном представлении, а обозначенный подтип A должен быть не ограничен.
Уровень доступности представления не должен быть статически глубже уровня типа доступа A.
Помимо мест, где обычно применяются правила законности (см. 12.3), эти требования также применяются в частях, закрытых от пользователя, экземпляра обобщенной единицы.
Выполняется проверка, что уровень доступности X не глубже уровня типа доступа A. Если эта проверка не пройдена, возникает ошибка Program_Error.
Если номинальный подтип X не статически совпадает с обозначенным подтипом A, оценивается преобразование представления X в обозначенный подтип (что может вызвать ошибку Constraint_Error — см. 4.6), и значение X'Access обозначает это представление.
Следующий атрибут определен для prefix P, обозначающего подпрограмму:
P'Access
Доступ P'Access возвращает значение доступа, которое обозначает подпрограмму, обозначенную P. Тип P'Access — это тип доступа к подпрограмме (S), определяемый ожидаемым типом. Уровень доступности P не должен быть статически глубже, чем у S. Если S неблокирующий, то P должен быть неблокирующим. В дополнение к местам, где обычно применяются правила законности (см. 12.3), эти правила применяются также в частях экземпляра обобщенного блока. Профиль P должен быть совместим по типу с обозначенным профилем S и не должен быть внутренним. Если подпрограмма, обозначенная P, объявлена внутри обобщенного блока, и выражение P'Access встречается внутри тела этого обобщенного блока или внутри тела обобщенного блока, объявленного внутри области описания обобщенного блока, то конечный предок S должен быть либо неформальным типом, объявленным внутри обобщенного блока, либо анонимным типом доступа параметра доступа.
Правила законности
Выражение считается имеющим распределённый доступ, если оно
- является условным выражением conditional_expression (см. 4.5.7); или
- является выражением объявления declare_expression (см. 4.5.9), у которого тело body_expression имеет распределённый доступ; или
- является преобразованием вида, qualified_expression или выражением в скобках, у которого операнд имеет распределённый доступ.
Статически более глубокое отношение не применяется к уровню доступа выражения expression с распределённым доступом; то есть такой уровень доступа не считается статически более глубоким или статически более поверхностным, чем любой другой.
Любое статическое требование к доступу, наложенное на выражение expression, имеющее распределённый доступ (или на его тип), вместо этого накладывается на зависимые_expressionы базового conditional_expression. Это правило применяется рекурсивно, если зависимое_expression также имеет распределённый доступ.
ПРИМЕЧАНИЕ 1 Атрибут Unchecked_Access возвращает тот же результат, что и атрибут Access для объектов, но имеет меньше ограничений (см. 13.10). Существуют и другие предопределённые операции, которые возвращают значения доступа: оператор выделения allocator может использоваться для создания объекта и возврата значения доступа, которое его обозначает (см. 4.8); вычисление литерала null возвращает значение доступа null, которое не обозначает никакого сущности (см. 4.2).
ПРИМЕЧАНИЕ 2 Предопределённые операции типа доступа также включают операцию присваивания, квалификацию и проверки принадлежности. Разрешено явное преобразование между общими типами доступа с соответствующими обозначаемыми подтипами; разрешено явное преобразование между типами доступа к подпрограммам с подтиповыми профилями (см. 4.6). Именные типы доступа имеют предопределённые операторы равенства; анонимные типы доступа не имеют, но они могут использовать предопределённые операторы равенства для universal_access (см. 4.5.2).
ПРИМЕЧАНИЕ 3 Объект или подпрограмма, обозначенные значением доступа, могут быть названы с помощью разыменования, либо explicit_dereference, либо implicit_dereference. См. 4.1.
ПРИМЕЧАНИЕ 4 Вызов через разыменование значения доступа к подпрограмме никогда не является вызовом диспетчеризации.
ПРИМЕЧАНИЕ 5 Атрибут Access для подпрограмм и параметров анонимного типа доступа к подпрограмме может использоваться вместе для реализации «замыканий вниз» — то есть для передачи подпрограммы более глубокого уровня вложенности в качестве параметра менее глубокой подпрограмме, что может быть уместно для абстракции итератора или численного интегрирования. Замыкания вниз также могут быть реализованы с помощью обобщённых формальных подпрограмм (см. 12.6). В отличие от объектов, нет атрибута Unchecked_Access для подпрограмм.
ПРИМЕЧАНИЕ 6 Использование типа доступа к межкассовому тегированному типу с операцией диспетчеризации — потенциально более структурированная альтернатива использованию типа доступа к подпрограмме.
ПРИМЕЧАНИЕ 7 Реализация может считать два значения доступа к подпрограммам разными, даже если они обозначают одну и ту же подпрограмму. Например, это может произойти, потому что одно указывает непосредственно на подпрограмму, а другое — на специальный пролог, который выполняет Elaboration_Check, а затем переходит к подпрограмме. См. 4.5.2.
Примеры
Пример использования атрибута Access:
Becky : Person_Name := new Person(F); -- см. 3.10.1
Cars : array (1..2) of aliased Car;
...
Becky.Vehicle := Cars(1)'Access;
Casey.Vehicle := Cars(2)'Access;
Cars : array (1..2) of aliased Car;
...
Becky.Vehicle := Cars(1)'Access;
Casey.Vehicle := Cars(2)'Access;