Справочник Ada 2012
3.10.2 Операции типов доступа
Атрибут Access используется для создания значений доступа, обозначающих объекты с алиасами и неинтринсивные подпрограммы. Правила «доступности» предотвращают «висячие ссылки» (в отсутствие использования определенных несверенных функций — см. Раздел 13).
Правила разрешения имен
Для attribute_reference с attribute_designator Access (или Unchecked_Access — см. 13.10), ожидаемый тип должен быть единственным типом доступа A таким, что:
- A является типом доступа к объекту с назначенным типом D, и типом префикса является D'Class или покрывается D, или
- A является типом доступа к подпрограмме, чья назначенная сигнатура соответствует типу префикса.
Префикс такого attribute_reference никогда не интерпретируется как неявная_дериференция или безаргументный вызов function_call (см. 4.1.4). Назначенный тип или сигнатура ожидаемого типа attribute_reference — это ожидаемый тип или сигнатура для префикса.
Статическая семантика
Правила доступности, предотвращающие «висячие ссылки», выражаются через уровни доступности, отражающие временное вложение мастеров. Как объясняется в 7.6.1, мастер — это выполнение определённого конструкта, например, subprogram_body. Уровень доступности глубее другого, если он вложен глубже во время выполнения. Например, объект, объявленный локально для вызываемой подпрограммы, имеет более глубокий уровень доступности, чем объект, объявленный локально для вызывающей подпрограммы. Правила доступности для типов доступа требуют, чтобы уровень доступности объекта, обозначенного значением доступа, не был глубже уровня доступа. Это гарантирует, что объект будет существовать как минимум столько же времени, сколько и тип доступа, что, в свою очередь, гарантирует, что значение доступа не может впоследствии обозначать объект, который больше не существует. Атрибут Unchecked_Access может использоваться для обхода правил доступности.
Дано, что один уровень доступности статически глубже другого, если данный уровень известен во время компиляции (как определено ниже) как более глубокий, чем другой, для всех возможных выполнений. В большинстве случаев доступность обеспечивается на этапе компиляции правилами легальности. Также используются проверки доступности во время выполнения, так как правила легальности не охватывают определённые случаи, включающие параметры доступа и обобщённые пакеты.
Каждый мастер, а также каждый созданный им элемент и представление, имеет уровень доступности:
- Уровень доступности данного мастера глубже, чем у каждого динамически окружающего мастера, и глубже, чем у каждого мастера, от которого задача, выполняющая данный мастер, непосредственно зависит (см. 9.3).
- Элемент или представление, определённый объявлением и созданный в рамках его обработки, имеет тот же уровень доступности, что и самый вложенный мастер объявления, за исключением случаев переименования и производных типов доступа, описанных ниже. За исключением явно алиасированного параметра функции или обобщённой функции, формальный параметр вызываемого элемента имеет тот же уровень доступности, что и мастер, представляющий вызов элемента.
- Уровень доступности представления объекта или подпрограммы, определённого renaming_declaration, такой же, как у переименованного представления.
- Уровень доступности преобразования доступа, qualified_expression или выражения в скобках такой же, как у операнда.
- Уровень доступности conditional_expression — это уровень доступности оцениваемого зависимого_выражения.
- Уровень доступности aggregate, который используется (полностью) для непосредственной инициализации части объекта, — это уровень объекта, который инициализируется. В других контекстах уровень доступности aggregate — это уровень самого вложенного мастера, который оценивает aggregate. Соответствующие правила применяются к преобразованию значения (см. 4.6).
- Уровень доступности результата вызова функции — это уровень мастера вызова функции, который определяется точкой вызова следующим образом:
Если результат используется (полностью) для непосредственной инициализации части объекта, мастер — это мастер объекта, который инициализируется. В случае, когда инициализируемый объект является корасширением (см. ниже), которое становится корасширением другого объекта, мастер — это мастер конечного объекта, которому будет передано корасширение.
Если результат имеет анонимный тип доступа и является операндом явного преобразования, мастер — это мастер целевого типа преобразования;
Если результат имеет анонимный тип доступа и определяет дискриминант доступа, мастер — тот же, что и для объекта, созданного анонимным allocator, который определяет дискриминант доступа (даже если результат доступа является типом доступа к подпрограмме).
Если сам вызов определяет результат функции, к которому применяется одно из вышеперечисленных правил, эти правила применяются рекурсивно;
В других случаях мастер вызова — это самый вложенный мастер, который оценивает вызов функции.
В случае вызова функции, тип результата которой является анонимным типом доступа, уровень доступности типа результата вызова функции также определяется точкой вызова, как описано выше.
- В операторе возврата уровень доступности объекта возврата — это уровень выполнения оператора возврата. Если оператор возврата завершается нормально, возвращаясь из функции, то перед выходом из функции уровень доступности объекта возврата изменяется на уровень, определяемый точкой вызова, как и уровень любых корасширений (см. ниже) объекта возврата.
- Уровень доступности производного типа доступа такой же, как у его конечного предка.
- Уровень доступности анонимного типа доступа, определённого access_definition object_renaming_declaration, такой же, как у переименованного представления.
- Уровень доступности анонимного типа доступа дискриминанта доступа в subtype_indication или qualified_expression allocator, или в выражении или return_subtype_indication оператора возврата определяется следующим образом:
Если значение дискриминанта доступа определяется discriminant_association в subtype_indication, уровень доступности объекта или подпрограммы, обозначенного связанным значением (или уровень библиотеки, если значение равно null);
Если значение дискриминанта доступа определяется default_expression в объявлении дискриминанта, уровень объекта или подпрограммы, обозначенного связанным значением (или уровень библиотеки, если null);
Если значение дискриминанта доступа определяется record_component_association в aggregate, уровень доступности объекта или подпрограммы, обозначенного связанным значением (или уровень библиотеки, если значение равно null);
В других случаях, где значение дискриминанта доступа определяется объектом с несогласованным номинальным подтипом, уровень доступности объекта.
- Уровень доступности анонимного типа доступа дискриминанта доступа в любом другом контексте — это уровень окружающего объекта.
- Уровень доступности анонимного типа доступа параметра доступа, указывающего тип доступа к объекту, совпадает с уровнем представления, обозначенным фактическим (или уровнем библиотеки, если фактический равен null).
- Уровень доступности анонимного типа доступа параметра доступа, указывающего тип доступа к подпрограмме, глубже, чем у любого мастера; все такие анонимные типы доступа имеют этот же уровень.
- Уровень доступности анонимного подтипа доступа, определённого return_subtype_indication, который является access_definition (см. 6.5), — это уровень подтипа результата вложенной функции.
- Уровень доступности типа автономного объекта анонимного типа доступа к объекту такой же, как уровень доступности типа значения доступа, наиболее недавно присвоенного объекту; проверки доступности гарантируют, что это никогда не будет глубже, чем объявление автономного объекта.
- Уровень доступности явно алиасированного (см. 6.1) формального параметра в теле функции определяется точкой вызова; он совпадает с уровнем, который в конечном итоге будет иметь возвращаемый объект.
- Уровень доступности объекта, созданного с помощью аллокатора, совпадает с уровнем типа доступа, за исключением аллокатора анонимного типа доступа (анонимного аллокатора) в определенных контекстах, как следует: для анонимного аллокатора, определяющего результат функции с результатом доступа, уровень доступности определяется так, как будто аллокатор заменяет вызов функции; в особом случае вызова, являющегося операндом преобразования типа, уровень равен типу доступа назначения преобразования. Для анонимного аллокатора, определяющего значение параметра доступа, уровень доступности равен уровню самого внутреннего мастера вызова. Для анонимного аллокатора, тип которого представляет собой самостоятельный объект анонимного типа доступа к объекту, уровень доступности равен уровню объявления самостоятельного объекта. Для аллокатора, определяющего дискриминант доступа, уровень доступности определяется следующим образом:
для аллокатора, используемого для определения дискриминанта объекта, уровень объекта;
для аллокатора, используемого для определения ограничения в индикации_типа_подтипа в любом другом контексте, уровень мастера, который обрабатывает индикацию_типа_подтипа.
Этот абзац был удалён.
В первом случае выделенный объект считается совместным расширением объекта, дискриминант которого его обозначает, а также любого объекта, которым дискриминированный объект является совместным расширением или подкомпонентом. Если выделенный объект является совместным расширением анонимного объекта, представляющего результат агрегата или вызова функции, который используется (полностью) для непосредственной инициализации части объекта, то после присвоения результата совместное расширение становится совместным расширением инициализируемого объекта и больше не считается совместным расширением анонимного объекта. Все совместные расширения объекта (которые не были перенесены такой инициализацией) завершаются при завершении объекта (см. 7.6.1).
- В инструкции return уровень доступности анонимного типа доступа к результату доступа равен уровню мастера вызова.
- Уровень доступности представления объекта или подпрограммы, обозначенного значением доступа, совпадает с уровнем типа доступа.
- Уровень доступности компонента, защищенной подпрограммы или входа (представления) составного объекта совпадает с уровнем (представления) составного объекта.
В вышеприведенных правилах операнд преобразования представления, скобочное выражение или квалифицированное_выражение рассматривается как используемое в контексте, если само преобразование представления, скобочное выражение или квалифицированное_выражение используются в этом контексте. Аналогично, зависимоевыражение условного_выражения считается используемым в контексте, если само условное_выражение используется в этом контексте.
Один уровень доступа определяется как статически глубже другого в следующих случаях:
- Для мастера, статически вложенного в другой мастер, уровень доступа внутреннего мастера статически глубже, чем уровень внешнего мастера.
- Уровень доступа анонимного типа доступа к параметру доступа, указывающему на тип доступа к подпрограмме, статически глубже, чем уровень любого мастера; все такие анонимные типы доступа имеют этот же уровень.
- Отношение статической глубинности не применяется к уровню доступа анонимного типа параметра доступа, указывающего на тип доступа к объекту, а также к потомку формального типа параметра; то есть такой уровень доступа не считается статически глубже, ни статически мельче, чем любой другой.
- Отношение статической глубинности не применяется к уровню доступа типа самостоятельного объекта анонимного типа доступа к объекту; то есть такой уровень доступа не считается статически глубже, ни статически мельче, чем любой другой.
- Внутри инструкции return, которая относится к функции или обобщенной функции F, или к выражению возврата выражения функции F, при определении, является ли уровень доступности явно алиасированного параметра F статически глубже уровня возвращаемого объекта F, уровень возвращаемого объекта считается таким же, как и уровень явно алиасированного параметра; для статического сравнения с уровнем других сущностей явно алиасированный параметр F считается имеющим уровень доступности тела F.
- При определении, является ли уровень статически глубже, чем уровень анонимного типа доступа к результату доступа функции или обобщенной функции F, когда внутри инструкции return, которая относится к F или к выражению возврата выражения функции F, уровень мастера вызова предполагается таким же, как уровень мастера, который обработав тело F.
- При определении, является ли один уровень статически глубже другого, когда внутри тела обобщенного пакета, обобщенный пакет предполагается экземпляризованным на том же уровне, где он был объявлен; проверки во время выполнения необходимы в случае более глубоких вложенных экземплиаций.
- При определении, является ли один уровень статически глубже другого, когда внутри области объявления объявления_типа, текущий экземпляр типа предполагается объектом, созданным на более глубоком уровне, чем уровень типа.
Уровень доступности всех модулей библиотеки называется уровнем библиотеки; объявление или сущность уровня библиотеки — это сущность, уровень доступности которой — уровень библиотеки.
Следующее атрибут определен для префикса 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 обозначает это представление.
Следующий атрибут определен для префикса P, обозначающего подпрограмму:
P'Access
P'Access возвращает значение доступа, обозначающее подпрограмму, обозначенную P. Тип P'Access — это тип доступа к подпрограмме (S), как определяется ожидаемым типом. Уровень доступа P не должен быть статически глубже, чем уровень S. В дополнение к местам, где обычно применяются Правила законности (см. 12.3), это правило также применяется в частной части экземпляра обобщенного модуля. Профиль P должен быть подтипово совместим с назначенным профилем S и не должен быть внутренним. Если подпрограмма, обозначенная P, объявлена в обобщенном модуле, а выражение P'Access встречается в теле этого обобщенного модуля или в теле обобщенного модуля, объявленного в области объявления обобщенного модуля, то конечный предок S должен быть либо типом, не являющимся формальным, объявленным в обобщенном модуле, либо анонимным типом доступа к параметру доступа.
Правила законности
Выражение считается имеющим распределенный доступ, если
- a conditional_expression (see 4.5.7); or
- a view conversion, qualified_expression, or parenthesized expression whose operand has distributed accessibility.
Статически более глубокое отношение не применяется к уровню доступа выражения, имеющего распределённый доступ; то есть, такой уровень доступа не считается ни статически более глубоким, ни статически менее глубоким, чем любой другой.
Любое статическое требование к доступу, которое налагается на выражение, имеющее распределённый доступ (или на его тип), вместо этого налагается на dependent_выражения основного conditional_expression. Это правило применяется рекурсивно, если dependent_выражение также имеет распределённый доступ.
ПРИМЕЧАНИЯ
91 Атрибут Unchecked_Access возвращает тот же результат, что и атрибут Access для объектов, но имеет меньше ограничений (см. 13.10). Существуют и другие предопределённые операции, которые возвращают значения доступа: allocator может быть использован для создания объекта и возврата значения доступа, которое его обозначает (см. 4.8); вычисление литерала null возвращает значение доступа null, которое не обозначает ни одного сущности (см. 4.2).
92 Предопределённые операции типа доступа также включают операцию присваивания, квалификацию и проверки принадлежности. Разрешено явное преобразование между общими типами доступа с совпадающими обозначенными подтипами; разрешено явное преобразование между типами доступа к подпрограммам с профилями подтипа (см. 4.6). Именованные типы доступа имеют предопределённые операторы равенства; анонимные типы доступа не имеют, но они могут использовать предопределённые операторы равенства для universal_access (см. 4.5.2).
93 Объект или подпрограмма, обозначенные значением доступа, могут быть названы с помощью разыменования, либо explicit_dereference, либо implicit_dereference. См. 4.1.
94 Вызов через разыменование значения доступа к подпрограмме никогда не является вызовом диспетчеризации.
95 Атрибут Access для подпрограмм и параметров анонимного типа доступа к подпрограмме могут быть вместе использованы для реализации «нисходящих замыканий» — то есть, для передачи более вложенной подпрограммы в качестве параметра менее вложенной подпрограмме, что может быть уместно для абстракции итератора или численного интегрирования. Нисходящие замыкания также могут быть реализованы с использованием формальных подпрограмм-параметров (см. 12.6). Обратите внимание, что Unchecked_Access не разрешено для подпрограмм.
96 Обратите внимание, что использование типа доступа к классу-wide с помеченным типом с операцией диспетчеризации является потенциально более структурированной альтернативой использованию типа доступа к подпрограмме.
97 Реализация может считать два значения доступа к подпрограмме различными, даже если они обозначают одну и ту же подпрограмму. Это может быть потому, что одно указывает непосредственно на подпрограмму, в то время как другое указывает на специальный пролог, который выполняет Elaboration_Check и затем переходит к подпрограмме. См. 4.5.2.
Примеры
Пример использования атрибута Access:
Martha : Person_Name := new Person(F); -- см. 3.10.1
Cars : array (1..2) of aliased Car;
...
Martha.Vehicle := Cars(1)'Access;
George.Vehicle := Cars(2)'Access;
Cars : array (1..2) of aliased Car;
...
Martha.Vehicle := Cars(1)'Access;
George.Vehicle := Cars(2)'Access;