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 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;
我还没弄明白该怎么做。
谢谢!
答案 0 :(得分:6)
由于循环依赖性,您无法创建要创建的结构。想一想:
通用包定义了一个指针。 Pointer_Type
(可能)的结构和实现取决于通用参数Item_Type
(这不一定是真的,但如果不是,则不需要Item_Type
通用参数)。现在,通用包实例化中的Item_Type
包含来自通用包的两个智能指针,因此取决于Pointer_Type
的结构。这是一个经典的鸡蛋或鸡蛋问题。
所以解决方案是改变你的类型的设计。让我给你一些指示(没有双关语):
看起来你正在实施一个双向链表。请注意,由于列表的循环特性,使用实现引用计数的智能指针是一个严重的错误。如果你的列表至少包含两个项目,那么任何东西都不会被释放,因为它们总是指向对方。因此,除非您的智能指针正在进行循环检测(根据您的规格不可能),否则您无法使用智能 指点你想要的方式。
一个可能的解决方案是拥有指向Item_Type
的智能指针,而不是记录。您需要手动取消分配记录,但无论如何都需要这样做,如上所述。
另一种解决方案是为整个列表提供一个全局引用计数器。创建一个不透明的列表类型,为列表提供访问器和迭代器子例程,分发项目的智能指针。智能指针增加和减少整个列表上的引用计数,一旦对列表的最后一次引用消失,整个列表将被释放。因此,只要存在至少一个对其中某些内容的引用,该列表就存在。此解决方案需要您自己实现引用计数,因为它专门用于列表结构。
最后,你可以使用Ada.Containers.Doubly_Linked_Lists
,就像杰弗里建议的那样。你可以在我的第一个解决方案中提出智能指针到那里的Item_Type
。
答案 1 :(得分:3)
为了使用智能指针进行操作,智能指针必须使用不完整的类型。因此,您还必须提供删除访问变量(当然还有访问类型)的终结过程。这当然也意味着您的分配函数需要采用访问类型而不是变量。最后,您绝对需要使用弱指针来打破引用计数智能指针生成的循环引用。
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;
然后你可以做类似的事情:
type Node_Impl;
type Node_Access is access Node_Impl;
procedure Finalize(Ref : in out Node_Access);
package Ptrs is new Pointers(Node_Impl,Node_Access,Finalize);
subtype Node is Ptrs.Smart_Pointer;
subtype Weak_Node is Ptrs.Weak_Pointer;
type Node_Impl is record
Value : Some_Type;
Next : Node;
Prev : Weak_Node;
end record;
这是我用来制作带有智能指针的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;
这很麻烦,但如果你想在Ada中使用智能指针制作自引用类型,则需要这样做。另请注意,如果在智能指针的规范中使用不完整类型,则某些版本的GNAT具有Implicit_Dereference方面的编译器错误。如果您使用的版本存在错误,它们将在编译时导致编译器崩溃。