【问题标题】:Ada initialization of controlled singleton variable受控单例变量的 Ada 初始化
【发布时间】:2015-10-25 06:18:31
【问题描述】:

我正在尝试使用自动初始化的单例变量创建一个包。如果单例变量不是受控类型,那么编译器不会抱怨,但是当我控制它时,我会收到警告:“在看到主体之前无法调用 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;

如何创建一个已初始化并在开始创建对象实例时可以使用的单例变量?提前致谢。

【问题讨论】:

  • 您是否有理由不使用通常的 Ada 实现单例模式? (即隐藏包体中的状态。)
  • 因为我希望子对象能够从这个单例中读取。我想我可以做一个访问函数。
  • 实际上,即使我将单例移到正文中,我也会收到相同的警告。
  • 但是你有没有把单例 after Initialize 移动到正文中?
  • 谢谢西蒙!成功了!

标签: singleton ada static-members static-initialization


【解决方案1】:

所提出的这个问题的答案是 - 正如编译器所说 - “在看到身体之前不能调用初始化”;也就是在 调用Initialize 的程序文本必须在 找到Initialize 正文的程序文本。这是一个 对one-pass compilers 的渴望的(可能是历史性的)后果。

因为Initialize 的主体必须出现在 包(除非它是 null,这在 Ada 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;

【讨论】:

    【解决方案2】:

    想到的解决方法:如果动态内存没有障碍,您可以在包的主体中分配对象,并且可以访问而不是常规实例供您的孩子查看。

    【讨论】:

    • 动态内存不是问题,我的问题好像是对象的创建时间。我的目标是在包含对象的任何实例或其子对象进入范围之前创建单例。
    • 这个想法(在规范中带有 pragma Elaborate_Body)难道不能满足这一点吗?
    最近更新 更多