Справочник по Ada 2005
3.10.2 Операции типов доступа
Атрибут Access используется для создания значений доступа, обозначающих алиасированные объекты и неявные подпрограммы. Правила «доступности» предотвращают висячие ссылки (при отсутствии использования определенных необязательных функций — см. раздел 13).
Правила разрешения имен
Для ссылка_на_атрибут с обозначение_атрибута Access (или Unchecked_Access — см. 13.10), ожидаемый тип должен быть единственным типом доступа A таким, что:
- A является типом доступа к объекту с указанным типом D и типом префикса D'Class или покрывается D, или
- A является типом доступа к подпрограмме, чья назначенная сигнатура совместима с сигнатурой префикса.
Префикс такой ссылка_на_атрибут никогда не интерпретируется как явное_разыменование или безаргументный вызов функции (см. 4.1.4). Назначенный тип или сигнатура ожидаемого типа ссылка_на_атрибут — это ожидаемый тип или сигнатура для префикса.
Статическая семантика
Правила доступности, предотвращающие висячие ссылки, выражены через уровни доступности, которые отражают временную вложенность главных элементов. Как объяснено в 7.6.1, главный элемент — это выполнение определённой конструкции, например, тела_подпрограммы. Уровень доступности глубже другого, если он более глубоко вложен во время выполнения. Например, объект, объявленный локально для вызываемой подпрограммы, имеет более глубокий уровень доступности, чем объект, объявленный локально для вызывающей подпрограммы. Правила доступности для типов доступа требуют, чтобы уровень доступности объекта, обозначенного значением доступа, не был глубже, чем уровень доступности типа доступа. Это гарантирует, что объект проживёт как минимум столько же, сколько тип доступа, что, в свою очередь, гарантирует, что значение доступа не будет в дальнейшем обозначать объект, который больше не существует. Атрибут Unchecked_Access может быть использован для обхода правил доступности.
Определённый уровень доступности считается статически более глубоким, чем другой, если данный уровень известен во время компиляции (как определено ниже) как более глубокий, чем другой, для всех возможных выполнений. В большинстве случаев доступность обеспечивается во время компиляции Правилами законности. Также используются проверки доступности во время выполнения, поскольку Правила законности не охватывают определённые случаи, включающие параметры доступа и обобщённые пакеты.
Каждый главный элемент и каждый созданный им элемент и представление имеет уровень доступности:
- Уровень доступности данного главного элемента глубже, чем уровень каждого динамически содержащего главного элемента и глубже, чем уровень каждого главного элемента, от которого напрямую зависит задача, выполняющая данный главный элемент (см. 9.3).
- Элемент или представление, определённые объявлением и созданные в ходе его разработки, имеют тот же уровень доступности, что и самый внутренний главный элемент объявления, за исключением случаев переименования и производных типов доступа, описанных ниже. Параметр главного элемента имеет тот же уровень доступности, что и главный элемент.
- Уровень доступности представления объекта или подпрограммы, определённого объявлением_переименования, совпадает с уровнем доступности переименованного представления.
- Уровень доступности преобразования представления, выражение_с_квалификатором или выражения в скобках — тот же, что и у операнда.
- Уровень доступности агрегата или результат вызова функции (или эквивалентного использования оператора), используемого (полностью) для непосредственной инициализации части объекта, совпадает с уровнем объекта, который инициализируется. В других контекстах уровень доступности агрегата или результата вызова функции — уровень самого внутреннего главного элемента, вычисляющего агрегат или вызов функции.
- В операторе возврата уровень доступности объекта возврата — уровень выполнения оператора возврата. Если оператор возврата завершается нормально, возвращаясь из функции, то перед выходом из функции уровень доступности объекта возврата изменяется на уровень, определяемый точкой вызова, как и уровень любых корасширений (см. ниже) объекта возврата.
- Уровень доступности производного типа доступа совпадает с уровнем его конечного предка.
- Уровень доступности анонимного типа доступа, определённого определением_доступа объявление_переименования_объекта, совпадает с уровнем доступности переименованного представления.
- Уровень доступности анонимного типа доступа дискриминанта доступа в индикации_типа или выражении_с_квалификатором аллокатора, или в выражении или индикации_типа_возврата оператора возврата определяется следующим образом:
- Если значение дискриминанта доступа определяется ассоциацией_дискриминанта в индикации_типа, уровень доступности объекта или подпрограммы, обозначенного связанным значением (или уровень библиотеки, если значение равно null);
- Если значение дискриминанта доступа определяется ассоциацией_компонента_записи в агрегате, уровень доступности объекта или подпрограммы, обозначенного связанным значением (или уровень библиотеки, если значение равно null);
- В других случаях, где значение дискриминанта доступа определяется объектом с неограниченным номинальным типом, уровень доступности объекта.
- Уровень доступности анонимного типа доступа дискриминанта доступа в любом другом контексте — уровень содержащего объекта.
- Уровень доступности анонимного типа доступа параметра доступа, указывающего тип доступа к объекту, совпадает с уровнем доступности представления, обозначенного фактическим.
- Уровень доступности анонимного типа доступа параметра доступа, указывающего тип доступа к подпрограмме, глубже, чем уровень любого главного элемента; все такие анонимные типы доступа имеют этот же уровень.
- Уровень доступности объекта, созданного аллокатором, совпадает с уровнем типа доступа, за исключением аллокатора анонимного типа доступа, который определяет значение параметра доступа или дискриминанта доступа. Для аллокатора, определяющего значение параметра доступа, уровень доступности — уровень самого внутреннего главного элемента вызова. Для аллокатора, определяющего дискриминант доступа, уровень доступности определяется следующим образом:
- для аллокатора, используемого для определения ограничения в объявлении_типа, уровень объявления_типа;
- для аллокатора, используемого для определения ограничения в определении_компонента, уровень содержащего типа;
- для аллокатора, используемого для определения дискриминанта объекта, уровень объекта.
-
В последнем случае, созданный объект называется корасширением объекта, дискриминант которого обозначает его, а также любого объекта, являющегося корасширением или подкомпонентом этого дискриминированного объекта. Все корасширения объекта завершаются, когда объект завершается (см. 7.6.1).
- Уровень доступности представления объекта или подпрограммы, обозначаемого разыменованием значения доступа, совпадает с уровнем доступности типа доступа.
- Уровень доступности компонента, защищённой подпрограммы или входа (представления) составного объекта совпадает с уровнем (представления) составного объекта.
В вышеуказанных правилах операнд преобразования представления, выражения в скобках или выражение_с_квалификатором считается используемым в контексте, если само преобразование представления, выражение в скобках или выражение_с_квалификатором используется в этом контексте.
Один уровень доступности определяется как статически более глубокий, чем другой в следующих случаях:
- Для мастера, который статически вложен внутри другого мастера, уровень доступности внутреннего мастера статически более глубокий, чем уровень внешнего мастера.
- Уровень доступности анонимного типа доступа параметра доступа, указывающего на тип доступа к подпрограмме, статически более глубокий, чем уровень любого мастера; все такие анонимные типы доступа имеют этот же уровень.
- Отношение статической глубины не относится к уровню доступности анонимного типа параметра доступа, указывающего на тип доступа к объекту; то есть, такой уровень доступности не считается статически более глубоким, ни статически более поверхностным, чем любой другой.
- Для определения, является ли один уровень статически более глубоким, чем другой, при нахождении внутри тела генерируемого пакета, предполагается, что генерируемый пакет инстанцирован на том же уровне, что и при его объявлении; при более глубоких вложенных инстанцированиях необходимы проверки во время выполнения.
- Для определения, является ли один уровень статически более глубоким, чем другой, при нахождении внутри декларативной области type_declaration, предполагается, что текущий экземпляр типа является объектом, созданным на более глубоком уровне, чем уровень типа.
Уровень доступности всех библиотек называется уровнем библиотеки; объявление или сущность на уровне библиотеки — это то, чьим уровнем доступности является уровень библиотеки.
Следующее атрибут определен для префикса 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 и не должен быть Intrinsic. Если подпрограмма, обозначаемая P, объявлена внутри генерируемого блока, и выражение P'Access встречается в теле этого генерируемого блока или в теле генерируемого блока, объявленного в декларативной области генерируемого блока, то конечный предок S должен быть либо типом, не являющимся формальным, объявленным внутри генерируемого блока, либо анонимным типом доступа параметра доступа.
ПРИМЕЧАНИЯ
84 Атрибут Unchecked_Access возвращает тот же результат, что и атрибут Access для объектов, но имеет меньше ограничений (см. 13.10). Существуют и другие предопределенные операции, возвращающие значения доступа: можно использовать аллокатор для создания объекта и возвращения значения доступа, которое его обозначает (см. 4.8); вычисление литерала null возвращает значение доступа null, которое не обозначает ни одного объекта (см. 4.2).
85 Предопределенные операции типа доступа также включают операцию присваивания, квалификацию и проверки принадлежности. Разрешено явное преобразование между общими типами доступа с соответствующими обозначенными подтипами; разрешено явное преобразование между типами доступа к подпрограмме с подтиповыми профилями (см. 4.6). Именованные типы доступа имеют предопределенные операторы равенства; анонимные типы доступа не имеют, но они могут использовать предопределенные операторы равенства для universal_access (см. 4.5.2).
86 Объект или подпрограмма, обозначаемая значением доступа, может быть названа с помощью разыменования, либо явного_разыменования, либо неявного_разыменования. См. 4.1.
87 Вызов через разыменование значения доступа к подпрограмме никогда не является вызовом диспетчеризации.
88 Атрибут Access для подпрограмм и параметров анонимного типа доступа к подпрограмме вместе могут быть использованы для реализации «вниз направленных замыканий» — т. е. для передачи более вложенной подпрограммы как параметра менее вложенной подпрограмме, что может быть уместно для абстракции итератора или численного интегрирования. Вниз направленные замыкания также могут быть реализованы с помощью формальных генерируемых подпрограмм (см. 12.6). Обратите внимание, что Unchecked_Access не разрешен для подпрограмм.
89 Обратите внимание, что использование типа доступа к классу-широкому помеченному типу с операцией диспетчеризации — это потенциально более структурированная альтернатива использованию типа доступа к подпрограмме.
90 Реализация может рассматривать два значения доступа к подпрограмме как неравные, даже если они обозначают одну и ту же подпрограмму. Это может быть потому, что один указывает непосредственно на подпрограмму, а другой — на специальный пролог, который выполняет 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;