【问题标题】:Passing array of aliased records to a procedure将别名记录数组传递给过程
【发布时间】:2015-08-04 14:59:06
【问题描述】:

在 Ada 2012 中,我希望在声明的数组内有一个链表,而不是分配。我想通过一个过程设置链接指针。

我已将我的程序简化为以下说明我想使用的原理,但我无法在 Raspi 上运行的 Gnat 4.9.2 (Debian Jessie) 中编译它...

procedure Arr is
   type Cell;
   type Cell_Ptr is access all Cell;

   type Cell is
      record
         Number : Integer := 0;
         Next : Cell_Ptr := null;
      end record;

   type Chain is array (1 .. 100) of aliased Cell;

   procedure Make_Links (Ch : in out Chain);

   procedure Make_Links (Ch : in out Chain) is
   begin
      for I in Ch'First .. Ch'Last - 1 loop
         Ch (I).Next := Ch (I + 1)'Access;                 -- ERROR HERE
      end loop;
   end Make_Links;

   My_Chain : Chain;
begin
   Make_Links (My_Chain);
end Arr;

我得到这个编译器错误: “non-local pointer cannot point to local object”在上面指出的那一行。

我知道我正在尝试做一些有点奇怪的事情,但我计划根据我将这个单元格数组传递给哪个过程以不同的方式(向后或随机等)执行链接的其他一些函数。

如何修复此代码以使其编译?无法完全理解这一点(我还是个新手,但很享受学习过程)。

【问题讨论】:

  • 我不确定这是否可行,但请尝试将参数更改为 Ch : access Chain 并将调用更改为 Make_Links (My_Chain'access)
  • ...当然,您必须将My_Chain 声明为aliased

标签: list pointers compilation ada


【解决方案1】:

由于您实际上并没有分配和释放内存,因此看不到指针的需要。我会通过执行以下操作来实现相同的功能:

procedure Arr is

   type Cell_Index is new Integer range 0 .. 100;
   subtype Valid_Cell_Index is Cell_Index range 1 .. Cell_Index'Last;

   type Cell is
      record
         Number : Integer := 0;
         Next   : Cell_Index := 0;
      end record;

   type Chain is array (Valid_Cell_Index) of Cell;

   procedure Make_Links (Ch : in out Chain);

   procedure Make_Links (Ch : in out Chain) is
   begin
      for I in Valid_Cell_Index'First .. Valid_Cell_Index'Last - 1 loop
         Ch (I).Next := I+1;
      end loop;
   end Make_Links;

   My_Chain : Chain;
begin
   Make_Links (My_Chain);

end Arr;

这样您仍然使用 Next 作为同一数组的索引,并且可以使用您想要的任何链接模式预加载您的数组。

【讨论】:

  • 是的,我通常会同意,但我必须简化我的真实源代码才能在此处发布。我有充分的理由尝试这样做,这只是我正在使用的语法。真正的代码(目前是“概念证明”模型)必须在具有 8 个单独指针的二维数组中执行此操作。最终代码会扩展为3维,每条记录26个指针!!!
  • 那么为什么不枚举你的指针,并拥有索引数组呢?您还可以将所有索引设置为父类型的子类型,这也应该防止无效索引。
  • 我不知道为什么不,真的。我会坚持下去的。
【解决方案2】:

不要使用’Access,而是使用’Unrestricted_Access。这是one of GNAT’s “implementation-defined” attributes

Unrestricted Access 属性与 Access 相似,只是省略了所有可访问性和别名视图检查。这是一个用户注意的属性。

【讨论】:

  • 在学习 Ada 的时候,我真的不想跳出“最佳实践”之外。必须有一个干净、安全的方法来做到这一点。我想使用 Ada,因为它有制衡机制来帮助我,我不想规避它们 :)
  • 如果你打算走这条路,为什么不使用'Unchecked_Access,它有一个Ada定义并且是可移植的,而不是GNAT特定的属性? 'Unchecked_Access 不会省略别名视图检查,但这不是问题。
  • @Wossname 可能是一种干净、安全的方法。不幸的是,Ada 的目标是提供一种安全的方式来进行这些访问检查,而无需在不需要时执行任何需要低效实施的操作,但事实证明对于一群凡人来说太难了。结果是 RM 3.10.2,被 Ada 专家称为“黑暗之心”。我邀请您尝试阅读它,但不是没有一瓶 Advil 手边。即便如此,我认为并不是每个用例都得到了充分处理。
  • @ajb 关于’Unchecked_Access 的说法是正确的,这会是一个更好的答案。
【解决方案3】:

最后我想通了。以下代码是 OP 中的代码的修改版本。它做了我最初想要的,没有做任何不愉快的事情......

with Ada.Integer_Text_IO, Ada.Text_IO;
use Ada.Integer_Text_IO, Ada.Text_IO;

procedure Arr is
   type Cell;
   type Cell_Ptr is access all Cell;

   type Cell is
      record
         Number : Integer := 0;
         Next : Cell_Ptr := null;
      end record;

   type Chain is array (1 .. 100) of aliased Cell;
   type Chain_Ptr is access all Chain;

   procedure Make_Links (CP : in out Chain_Ptr);

   procedure Make_Links (CP : in out Chain_Ptr) is
   begin
      for I in CP'First .. CP'Last - 1 loop
         CP.all (I).Next := CP.all (I + 1)'Access;
      end loop;
   end Make_Links;

   My_Chain : aliased Chain;
   My_CP : Chain_Ptr := null;
   My_C : Cell_Ptr := null;
begin
   My_CP := My_Chain'Access;
   Make_Links (My_CP);

   --  verify that the code works by writing values into the array
   for I in My_Chain'Range loop
      My_Chain (I).Number := 1000 * I;
   end loop;

   --  and read them back out using the pointer links
   My_C := My_Chain (My_Chain'First)'Access;
   while My_C /= null loop
      Put (My_C.Number);
      Put_Line ("");
      My_C := My_C.Next;
   end loop;

end Arr;

我没有直接传递数组,而是传递了一个指向数组的指针,Gnat 似乎对此很满意。我认为我之前尝试做的事情被过程参数的“通过复制”规则所破坏。

【讨论】:

  • 我不认为“通过复制”规则与它有任何关系。这都是关于可访问性规则的。当您将Chain 作为参数时,您可以传递在深度嵌套的内部过程中声明的Chain,这是一个问题,因为元素上的'Access 可以存储指向对象的指针在物体消失后可以存活。 Chain_Ptr 不能这样做,因为 Chain_Ptr 不允许指向比 Chain_Ptr 声明嵌套更深的任何内容。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-07-09
  • 1970-01-01
  • 2016-04-27
  • 1970-01-01
相关资源
最近更新 更多