我正在努力摆脱短线串。 目前在我们的计划中使用的很多地方之一是记录。 很多这些记录保存在AVL树中。
使用的AVL树是一个通用树,它包含一个指向多个字节(ElemSize
)的指针,这些字节到目前为止运行良好。
AVL树中每条记录的内存分配为GetMem
,并使用Move
进行复制。
但是,如果string是指向引用计数结构的指针,则将内存复制回记录不再有效,因为引用的sting经常被释放(通过引用计数自动)。
只有一个指针和"数据块"的大小,我认为不可能增加字符串的引用计数。
我正在寻找一种方法来获取将记录存储在AVL树中时要考虑的叮咬的引用计数。
我可以将记录类型传递给树构造函数,然后将指针强制转换为此类型,从而增加引用吗?或者类似的修复,我可以将更改主要放在AVL单元中并调用它的构造函数。
用于分配以AVL存储记录的空间的当前代码; XData是指向要存储的记录的指针:
New(RootPtr); { create new memory space }
GetMem(RootPtr^.TreeData, ElemSize);
WITH RootPtr^ DO BEGIN
{ copy data }
Move(XData^, RootPtr^.TreeData^, ElemSize);
答案 0 :(得分:5)
从本质上讲,你问的问题是:
当我知道其类型的大小是什么时,我如何分配,复制和取消分配记录?
简单的答案是,如果记录不包含托管类型,您可以使用GetMem
,Move
和FreeMem
。您希望使用包含Delphi字符串的记录,这些字符串是受管理的。因此,使用GetMem
和Move
的当前方法是不够的。
有很多方法可以解决这个问题。您可以编写自己的代码来进行引用计数,只要您知道托管类型在记录中的位置即可。我不推荐这个。您可以将您的用户数据设为一个类,并使用多态来提供帮助。
我想讨论的选项继续支持记录,并且确实允许用户选择他们喜欢的任何类型。理由如下:
如果类型包含托管类型,则对其进行操作需要了解类型。如果树是通用的,那么它就不具备这种知识。因此,知识必须由树的用户提供。
这会引导您参加活动。让树提供用户可以提供处理程序的事件。类型如下所示:
type
PTreeNodeUserData = type Pointer;
TTreeNodeCreateUserDataEvent = function: PTreeNodeUserData of object;
TTreeNodeDestroyUserDataEvent = procedure(Data: PTreeNodeUserData) of object;
TTreeNodeCopyUserDataEvent = procedure(Source, Dest: PTreeNodeUserData) of object;
然后,您可以安排您的树发布具有用户可以订阅的这些类型的事件。
关键在于,这允许树的用户提供有关用户数据类型的缺失知识。
答案 1 :(得分:4)
使用记录的一个主要好处是可以简单地复制它们(不使用Move
)。因此,您最好的解决方案是将Move
替换为普通赋值运算符:=
。这将正确考虑所涉及的所有托管类型的引用计数。
您是否有特殊原因未使用普通赋值运算符?
PS :您需要确保正确初始化并最终确定所有托管类型(包括长字符串)的内存。我建议你对Initialize
和Finalize
例程做一些额外的阅读。
树是通用的,它可以保存给定的数据块。我希望我可以扩展功能而不需要为每条记录创建一个新的树类。
在这种情况下,您需要根据其使用的内容来改变“复制行为”。作为几个选项:
如果您的树被包装在一个类中,您可以轻松地修改它以使用回调事件来执行复制操作。 (即使您首先必须将树封装在类中,此选项可能也是最简单的。)
将节点和/或数据修改为具有多态复制功能的对象。然后每个子类型都知道如何正确复制自己,你可以写一些Root.TreeData := XData.CreateCopy;
答案 2 :(得分:2)
如果您的工作水平较低,并且不希望编译器为您提供帮助,那么您需要使用PChar-strings而不是常规字符串。