Ада инициализация управляемой переменной синглтона

Я пытаюсь создать пакет с одноэлементной переменной, которая автоматически инициализируется. Если переменная 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;

Обходное решение, которое приходит на ум: если динамическая память не является препятствием, вы можете выделить объект в теле пакета и иметь доступ вместо обычного экземпляра для просмотра вашими детьми.

Другие вопросы по тегам