我的情况很复杂,所以我希望能够妥善解释。
我将unchecked_access与Ada.Finalization.Controlled类型结合使用,将对vector的引用传递给Initialize过程中超出范围的受保护哈希映射类型,并在finalize过程中删除受保护映射中的引用。这样我认为我可以确保任何任务都不可能看到地图中的范围引用。
然而,我使用受保护地图组织快照的方式是在它使用的每个实例(有效地使它成为普通的hashed_map)中拍摄的,在使用它的过程中,矢量引用可能超出范围和快照镜头仍会有参考并尝试访问它。
我可以看到这会产生2个问题,要么我正在创建悬空指针并试图引用释放的内存,要么我的引用快照保持内存存活并且我要留下垃圾。我做了一个测试,看看会发生什么,看起来内存仍然存在,但这是真的吗?我的组织还有其他问题吗?
with Ada.Containers; use Ada.Containers;
with Ada.Containers.Vectors;
with Ada.Text_IO; use Ada.Text_IO;
procedure Test is
package V_Integer is new Ada.Containers.Vectors(Positive, Integer);
use V_Integer;
type V_Access is access all Vector;
Bar : V_Access;
begin
declare
Foo : aliased Vector;
begin
Bar := Foo'unrestricted_Access;
Foo.Append(3);
Foo.Append(5);
Put_Line("In scope: " & count_type'image(Length(Bar.all)));
end;
-- Will this reference always exist? Does it need to be freed?
Put_Line("Out of scope: " & count_type'image(Length(Bar.all)));
end Test;
答案 0 :(得分:2)
begin
declare
Foo : aliased Vector;
begin
Bar := Foo'unrestricted_Access;
Foo.Append(3);
Foo.Append(5);
Put_Line("In scope: " & count_type'image(Length(Bar.all)));
end;
-- Will this reference always exist? Does it need to be freed?
Put_Line("Out of scope: " & count_type'image(Length(Bar.all)));
end Test;
Foo
将是Vector
类型的对象,它可能存在于堆栈中。这个对象本身就是一个相对较小的记录,在GNAT中可能大约有6个32位的单词(给出或拿走一些,我还没有检查过)。它包含一个访问组件,用于获取所有向量的元素,并包含一些其他内务处理信息。 Bar
将指向那个小的6个字的记录。基本上它将包含堆栈中某些东西的地址。
由于堆栈上存在小记录Foo
,当它超出范围时,堆栈空间可用于其他内容。在这种情况下是否会发生,我不知道。但是如果在示例中的块后面有另一个declare...begin...end
块,则新块使用的局部变量可以重用相同的堆栈空间。或者如果调用了一个过程,那么会在堆栈中放入不同的东西。在任何一种情况下,Foo
以前使用的堆栈空间都将被覆盖。并且Bar
仍将指向相同的地址,但它指向的区域将被其他数据覆盖。所以结果可能是错误的,可能是一场灾难。
我不知道这究竟是如何实现的,但无论它是如何实现的,这段代码都可能是灾难性的。要记住的主要事项是:(1)如果变量超出范围,则可以随意重用用于该变量的空间; (2)如果你使用'Unchecked_Access
(或'Unrestricted_Access
)来设置指向该变量的指针,那么在变量超出范围之后,访问指针所指向的数据可能会让你变得垃圾或非常不良行为; (3)变量,无论是否有别名,都不会(通常)动态分配,并且程序不需要(也不能)明确地释放它们,即使您已使用'Unchecked_Access
创建了对它们的引用