Generics Ada:泛型、不完整类型和自引用结构的困难
在Ada中,这样做很简单:Generics Ada:泛型、不完整类型和自引用结构的困难,generics,package,packages,ada,Generics,Package,Packages,Ada,在Ada中,这样做很简单: type ITEM_RECORD; type ITEM_ACCESS is access ITEM_RECORD; type ITEM_RECORD Is record ITEM: item_type; Next: item_access; Pred: item_access; end record; 简单,对吗?现在,如果我想让ITEM_ACCESS成为在通用包中声明的智能/安全指针,该怎么办?我直觉上是这样做的,只要它起作用: type ITE
type ITEM_RECORD;
type ITEM_ACCESS is access ITEM_RECORD;
type ITEM_RECORD Is
record
ITEM: item_type;
Next: item_access;
Pred: item_access;
end record;
简单,对吗?现在,如果我想让ITEM_ACCESS成为在通用包中声明的智能/安全指针,该怎么办?我直觉上是这样做的,只要它起作用:
type ITEM_access;
type Item_Record is record
Item : Item_Type;
Next : Item_Access;
Pred : Item_Access;
end record;
type pointers_on_record is access Item_record;
package pointers_p is new pointers(Item_Record, pointers_on_record);
type item_access is new pointers_p.Pointer_Type;
通用标准的规范如下:
generic
type Item_Type(<>) is limited private;
type Access_Type is access Item_Type;
package Pointers is
type Pointer_Type is private;
通用
类型项_type()是有限的私有类型;
类型访问\类型为访问项\类型;
包指针是
类型指针\u类型为私有类型;
我还不知道怎么做
谢谢 由于循环依赖关系,无法创建要创建的结构。想想看: 泛型包定义一个指针。
指针类型
(可能)的结构和实现取决于通用参数项类型
(这不一定是真的,但如果不是真的,则不需要将项类型
作为通用参数)。现在,泛型包实例化中的Item\u Type
包含来自泛型包的两个智能指针,因此取决于Pointer\u Type
的结构。这是一个典型的鸡或蛋的问题
因此,解决方案是更改类型的设计。让我给你一些建议(没有双关语):
看起来您正在实现一个双链接列表。请注意,由于列表的循环性质,使用实现引用计数的智能指针是一个严重的错误。如果您的列表中至少有两个项目,则不会解除分配任何内容,因为它们始终指向对方。因此,除非您的智能指针正在执行循环检测(根据您的规范,这是不可能的),否则您不能使用智能指针
按您想要的方式指示
一个可能的解决方案是使用智能指针指向项目类型
,而不是记录。您将需要手动取消分配记录,但仍需要按照上面的说明执行此操作
另一种解决方案是为整个列表设置一个全局引用计数器。创建一个不透明的列表类型,该类型为列表提供访问器和迭代器子例程,这些子例程向项目发出智能指针。智能指针增加和减少整个列表上的引用计数,一旦最后一个对列表的引用消失,整个列表将被释放。因此,只要列表中至少有一个引用存在,列表就存在。此解决方案需要您自己实现引用计数,因为它专门用于列表结构
最后,您当然可以使用
Ada.Containers.double\u Linked\u list
,就像Jeffrey建议的那样。正如我在第一个解决方案中所建议的那样,您可以将智能指针放在您的项目类型中。要使用智能指针,您的智能指针必须使用不完整的类型。因此,您还必须提供一个删除访问变量(当然还有访问类型)的终结过程。当然,这也意味着您的分配函数需要采用访问类型而不是变量。最后,您绝对需要使用弱指针来打破由引用计数智能指针生成的循环引用
generic
type Item_Type(<>);
type Item_Access is access Item_Type;
with procedure Finalize(Ref : in out Item_Access);
package Pointers is
function Make(Ref : not null Item_Access) return Smart_Pointer;
-- other stuff
end Pointers;
下面是一个示例规范,我使用它创建了一个带有智能指针的AVL树。我手头没有链表示例
package Trees is
type Node;
type Node_Access is access Node;
procedure Finalize(Memory : in out Node_Access);
package Node_Smart_Access is new Smart_Access
(Item_Type => Node,
Item_Access => Node_Access,
Finalize => Finalize,
Atomic_Increment => True);
type Node is record
Value : Integer := 0;
Height : Integer := 1;
Parent : Node_Smart_Access.Weak_Access;
Left : Node_Smart_Access.Shared_Access;
Right : Node_Smart_Access.Shared_Access;
end record;
type Tree is tagged record
Root : Node_Smart_Access.Shared_Access;
end record;
end Trees;
我的智能指针规范是:
generic
type Item_Type(<>);
type Item_Access is access Item_Type;
with procedure Finalize(Memory : in out Item_Access);
Atomic_Increment : Boolean := True;
package Smart_Access is
type Shared_Access is new Ada.Finalization.Controlled with private;
type Weak_Access is new Ada.Finalization.Controlled with private;
-- more stuff
package Make is
function Shared_Access
(Source : in not null Item_Access)
return Smart_Access.Shared_Access;
-- more stuff
end Make;
private
-- implementation
end Smart_Access;
通用
输入Item_type();
类型项访问为访问项类型;
带程序完成(内存:输入输出项访问);
原子增量:布尔:=真;
软件包智能访问是
类型Shared_Access是新的Ada.Finalization.Controlled with private;
类型弱_访问是新的Ada.Finalization.Controlled with private;
--更多的东西
包装制造是
功能共享访问
(来源:在非空项_访问中)
返回智能访问。共享访问;
--更多的东西
成品;
私有的
--实施
终端智能接入;
这很麻烦,但如果您想在Ada中使用智能指针创建自引用类型,则需要这样做。还请注意,如果在智能指针的规范中使用不完整的类型,则GNAT的某些版本会出现隐式解引用方面的编译器错误。如果您使用的版本存在错误,则在编译时,它们将导致编译器崩溃。是否正在创建双链接列表?为什么?Ada.Containers.Double链接列表有什么问题?错误是什么?因此,正如预期的那样,解决方案是。。。你不能。不知何故,这并不让我感到惊讶:-D。你的主要观点是,在这里放置智能指针是一个设计错误。这使我信服了。我没有使用标准容器,因为这是一个书本练习,你被告知要把它们写成容器;-)我只是想知道我到底错在哪里。我不知道智能指针的设计是否会根据它所使用的数据结构而改变。但这显然是有道理的。太棒了。我开始理解不完整的泛型参数是用来做什么的。实际上,客户机可能会将其实例化为有限的不确定类型,因为任何类型(不包括不完全类型)都可以与未经检查的释放一起使用。您的示例之所以有效,是因为访问类型的大小始终相同(等等……从技术上讲,这不是假的吗?根据类型,边界可以存储到指针中,对吗?泛型如何处理这一事实?该示例适用于任何类型。编译器不需要知道访问类型的大小,直到包被实例化,然后它才知道。访问类型c是正确的一个类型有不同的大小,但对于泛型形式,它在实例化之前并不关心实际大小(正如我所说的,到那时它就知道了)。编译器在实例化之前不会尝试构建任何类型。
generic
type Item_Type(<>);
type Item_Access is access Item_Type;
with procedure Finalize(Memory : in out Item_Access);
Atomic_Increment : Boolean := True;
package Smart_Access is
type Shared_Access is new Ada.Finalization.Controlled with private;
type Weak_Access is new Ada.Finalization.Controlled with private;
-- more stuff
package Make is
function Shared_Access
(Source : in not null Item_Access)
return Smart_Access.Shared_Access;
-- more stuff
end Make;
private
-- implementation
end Smart_Access;