Ада инициализация управляемой переменной синглтона
Я пытаюсь создать пакет с одноэлементной переменной, которая автоматически инициализируется. Если переменная singleton не является контролируемым типом, то компилятор не будет жаловаться, но когда я сделаю его управляемым, я получу предупреждение:"не могу вызвать Initialize до того, как тело увидит"
Далее следует:"Ошибка программы будет возникать во время выполнения".
Итак, я думаю, что компилятор хочет, чтобы переменная-одиночка была скрыта от дочерних объектов, но это не то, что я хочу. Вот мой код:
with Ada.Finalization;
package static_member is
type singleton_type is tagged limited private;
private
type singleton_type is new Ada.Finalization.Limited_Controlled with record
data_to_init: Natural;
end record;
overriding procedure Initialize(data: in out singleton_type);
overriding procedure Finalize(data: in out singleton_type);
--This is where I get the warnings.
--I want singleton to be visible to child objects.
singleton: singleton_type;
end static_member;
Тогда тело пакета:
package body static_member is
overriding procedure Initialize(data: in out singleton_type) is
begin
data.data_to_init := 0;
end Initialize;
overriding procedure Finalize(data: in out singleton_type) is null;
end static_member;
Как создать единственную переменную, которая инициализируется и готова к использованию к моменту создания экземпляров объекта? Заранее спасибо.
2 ответа
Ответ на поставленный вопрос заключается в том, что, как сказал компилятор, "нельзя вызвать Initialize до того, как тело увидит"; то есть место в тексте программы, где Initialize
Вызывается должен быть после того места в тексте программы, где тело Initialize
найден. Это (возможно, историческое) следствие желания однопроходных компиляторов.
Потому что тело Initialize
должен появиться в теле пакета (если это не ноль, что является законным в Аде 2012), это означает, что singleton
может быть объявлено только в теле пакета (после тела Initialize
, конечно).
Это означает, что вам нужно предоставить подпрограммы доступа для использования дочерними пакетами: возможно
with Ada.Finalization;
package Static_Member with Elaborate_Body is
type Singleton_Type is tagged limited private;
function Singleton return access Singleton_Type;
private
type Singleton_Type is new Ada.Finalization.Limited_Controlled with record
Data_To_Init: Natural;
end record;
overriding procedure Initialize (Data: in out Singleton_Type);
overriding procedure Finalize (Data: in out Singleton_Type);
end Static_Member;
package body Static_Member is
overriding procedure Initialize (Data: in out Singleton_Type) is
begin
Data.Data_To_Init := 0;
end Initialize;
overriding procedure Finalize (Data: in out Singleton_Type) is null;
The_Singleton: aliased Singleton_Type;
function Singleton return access Singleton_Type is (The_Singleton'Access);
end Static_Member;
Причина для Elaborate_Body
в том, что без него компилятор не должен разрабатывать тело пакета раньше, чем другие, используя пакеты, которые вызывают подпрограммы пакетов (например, Singleton
): так
The_Singleton: aliased Singleton_Type;
с неявным призывом к Initialize
возможно, не произошло (что привело бы к Program_Error
с другой причиной, известной в торговле как "доступ до разработки" или ABE).
Тем не менее, есть и другие подходы, которые избегают использованияAda.Finalization
, Ваш пример кода не показывает какой-либо конкретной причины его использовать, и действительно, нет смысла переопределять Finalize
(разве вы не хотите, чтобы что-то происходило при завершении работы программы?)
Одна возможность (для простого случая) будет объявитьSingleton_Type
с инициализацией:
type Singleton_Type is record
Data_To_Init : Natural := 0;
end record;
Альтернативой может быть инициализация в теле пакета:
package Static_Member with Elaborate_Body is
type Singleton_Type is limited private;
function Singleton return access Singleton_Type;
private
type Singleton_Type is limited record
Data_To_Init : Natural;
end record;
end Static_Member;
package body Static_Member is
The_Singleton: aliased Singleton_Type;
function Singleton return access Singleton_Type is (The_Singleton'Access);
begin
The_Singleton.Data_To_Init := 0;
end Static_Member;
Обходное решение, которое приходит на ум: если динамическая память не является препятствием, вы можете выделить объект в теле пакета и иметь доступ вместо обычного экземпляра для просмотра вашими детьми.