Справочник по Ada (Ada 2022)
4.8 Распределители
Вычисление распределителя создаёт объект и возвращает значение доступа, которое обозначает этот объект.
Синтаксис
распределитель ::=
new [спецификация_подпула] индикация_подтипа
| new [спецификация_подпула] квалифицированное_выражение
new [спецификация_подпула] индикация_подтипа
| new [спецификация_подпула] квалифицированное_выражение
Правила разрешения имён
Ожидаемый тип для распределителя должен быть единственным типом доступа к объекту со свойственным типом D, причём либо D покрывает тип, определяемый маркой_подтипа индикации_подтипа или квалифицированным_выражением, либо ожидаемый тип является анонимным, а определённый тип — D'Class. указатель_подпула_имя ожидается быть любого типа, произошедшего от Subpool_Handle, который используется для идентификации подпула, объявленного в пакете System.Storage_Pools.Subpools (см. 13.11.4).
Правила легальности
Инициализированный распределитель — это распределитель с квалифицированным_выражением. Неинициализированный распределитель — это распределитель с индикацией_подтипа. В индикации_подтипа неинициализированного распределителя ограничение разрешается только в том случае, если марка_подтипа обозначает нескомпонованный составной подтип; если нет ограничения, то марка_подтипа должна обозначать определённый подтип.
Если тип распределителя — тип доступа к константе, то распределитель должен быть инициализированным распределителем.
Если указана спецификация_подпула, тип хранилища пула для типа доступа должен быть потомком Root_Storage_Pool_With_Subpools.
Если определяемый тип типа распределителя — общий класс, уровень доступности типа, определяемого индикацией_подтипа или квалифицированным_выражением, не должен быть статически глубже, чем уровень доступности типа распределителя.
Если подтип, определяемый индикацией_подтипа или квалифицированным_выражением распределителя, имеет один или несколько дискриминантов доступа, то уровень доступности анонимного типа доступа каждого дискриминанта доступа не должен быть статически глубже, чем уровень доступности типа распределителя (см. 3.10.2).
Распределитель не должен быть типа доступа, для которого Storage_Size указан статическим выражением с значением ноль или определён языком как ноль.
Если определяемый тип типа распределителя ограничен, то распределитель не должен использоваться для определения значения дискриминанта доступа, если только дискриминируемый тип не является неизменно ограниченным (см. 7.5).
Помимо мест, где обычно применяются правила легальности (см. 12.3), эти правила применяются также в частной части экземпляра генерируемого модуля.
Статическая семантика
Если определяемый тип типа распределителя — элементарный, то подтип создаваемого объекта — определяемый подтип. Если определяемый тип — составной, то подтип создаваемого объекта — определяемый подтип, когда определяемый подтип ограничен или есть предок определяемого типа, имеющий ограниченный частичный вид; в противном случае создаваемый объект ограничен его начальным значением (даже если определяемый подтип не ограничен со значениями по умолчанию).
Динамическая семантика
При вычислении инициализированного распределителя сначала выполняется вычисление квалифицированного_выражения. Создаётся объект определяемого типа, и значение квалифицированного_выражения преобразуется в определяемый подтип и присваивается объекту.
При вычислении неинициализированного распределителя сначала выполняется разработка индикации_подтипа. Затем:
- Если определяемый тип — элементарный, создаётся объект определяемого подтипа, и ему присваивается любое неявное начальное значение;
- Если определяемый тип — составной, создаётся объект определяемого типа со знаком, если таковой имеется, определяемый маркой_подтипа индикации_подтипа. Этот объект затем инициализируется по умолчанию (см. 3.3.1) с использованием индикации_подтипа для определения его номинального подтипа. Проверяется, принадлежит ли значение объекта определяемому подтипу. Если проверка не пройдена, возникает Constraint_Error. Эта проверка и инициализация объекта выполняются в произвольном порядке.
Для любого распределителя, если определяемый тип типа распределителя — общий класс, то проверяется, что мастер типа, определяемого индикацией_подтипа или знаком значения квалифицированного_выражения, включает разработку типа распределителя. Если какая-либо часть подтипа, определяемого индикацией_подтипа или квалифицированным_выражением распределителя (или знаком значения, если тип квалифицированного_выражения общий), имеет один или несколько дискриминантов доступа, то проверяется, что уровень доступности анонимного типа доступа каждого дискриминанта доступа не глубже, чем уровень доступности типа распределителя. Если какая-либо такая проверка не пройдена, возбуждается Program_Error.
Если создаваемый объект распределителем содержит управляемую или защищённую часть, и завершение сбора типа распределителя (см. 7.6.1) началось, то возбуждается Program_Error.
Если объект, создаваемый распределителем, содержит задачи, и мастер типа распределителя завершён, и все зависимые задачи мастера завершены (см. 9.3), то возбуждается Program_Error.
Если распределитель включает указатель_подпула_имя, Constraint_Error возбуждается, если указатель подпула равен null. Program_Error возбуждается, если подпул не принадлежит (см. 13.11.4) хранилищу пула типа доступа распределителя.
Если создаваемый объект содержит задачи, они активируются (см. 9.2). Наконец, возвращается значение доступа, которое обозначает созданный объект.
END_OF_DOCUMENT_MARKER Ограниченные (временно́й) ошибки
Ошибка является ограниченной, если завершение инициализации коллекции типа (см. 7.6.1) распределителя началось. Если ошибка обнаружена, генерируется Program_Error. В противном случае выделение памяти происходит нормально.
ПРИМЕЧАНИЕ 1 Распределители не могут создавать объекты абстрактного типа. См. 3.9.3.
ПРИМЕЧАНИЕ 2 Если какая-либо часть созданного объекта контролируется, инициализация включает вызовы соответствующих процедур Initialize или Adjust. См. 7.6.
ПРИМЕЧАНИЕ 3 Как объяснено в 13.11, «Управление памятью», память для объекта, выделенного распределителем, берётся из пула памяти (возможно, заданного пользователем). Исключение Storage_Error генерируется распределителем, если памяти недостаточно. Экземпляры Unchecked_Deallocation могут быть использованы для явного освобождения памяти.
ПРИМЕЧАНИЕ 4 Реализации могут, при необходимости, предоставлять сборку мусора.
Примеры
Примеры распределителей:
new Cell'(0, null, null) -- инициализировано явно, см. 3.10.1
new Cell'(Value => 0, Succ => null, Pred => null)
-- инициализировано явно
new Cell -- не инициализировано
new Cell'(Value => 0, Succ => null, Pred => null)
-- инициализировано явно
new Cell -- не инициализировано
new Matrix(1 .. 10, 1 .. 20) -- заданы только границы
new Matrix'(1 .. 10 => (1 .. 20 => 0.0)) -- инициализировано явно
new Matrix'(1 .. 10 => (1 .. 20 => 0.0)) -- инициализировано явно
new Buffer(100) -- задан только дискриминант
new Buffer'(Size => 80, Pos => 0, Value => (1 .. 80 => 'A'))
-- инициализировано явно
new Buffer'(Size => 80, Pos => 0, Value => (1 .. 80 => 'A'))
-- инициализировано явно
Expr_Ptr'(new Literal)
-- распределитель для доступа к типу класса, см. 3.9.1
Expr_Ptr'(new Literal'(Expression with 3.5)) -- инициализировано явно
-- распределитель для доступа к типу класса, см. 3.9.1
Expr_Ptr'(new Literal'(Expression with 3.5)) -- инициализировано явно