字符串生存期管理,在记录中

时间:2014-05-05 06:55:58

标签: delphi record delphi-2007 reference-counting

我正在努力摆脱短线串。 目前在我们的计划中使用的很多地方之一是记录。 很多这些记录保存在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);

3 个答案:

答案 0 :(得分:5)

从本质上讲,你问的问题是:

  

当我知道其类型的大小是什么时,我如何分配,复制和取消分配记录?

简单的答案是,如果记录不包含托管类型,您可以使用GetMemMoveFreeMem。您希望使用包含Delphi字符串的记录,这些字符串是受管理的。因此,使用GetMemMove的当前方法是不够的。

有很多方法可以解决这个问题。您可以编写自己的代码来进行引用计数,只要您知道托管类型在记录中的位置即可。我不推荐这个。您可以将您的用户数据设为一个类,并使用多态来提供帮助。

我想讨论的选项继续支持记录,并且确实允许用户选择他们喜欢的任何类型。理由如下:

如果类型包含托管类型,则对其进行操作需要了解类型。如果树是通用的,那么它就不具备这种知识。因此,知识必须由树的用户提供。

这会引导您参加活动。让树提供用户可以提供处理程序的事件。类型如下所示:

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 :您需要确保正确初始化并最终确定所有托管类型(包括长字符串)的内存。我建议你对InitializeFinalize例程做一些额外的阅读。


  

树是通用的,它可以保存给定的数据块。我希望我可以扩展功能而不需要为每条记录创建一个新的树类。

在这种情况下,您需要根据其使用的内容来改变“复制行为”。作为几个选项:

  1. 如果您的树被包装在一个类中,您可以轻松地修改它以使用回调事件来执行复制操作。 (即使您首先必须将树封装在类中,此选项可能也是最简单的。)

  2. 将节点和/或数据修改为具有多态复制功能的对象。然后每个子类型都知道如何正确复制自己,你可以写一些Root.TreeData := XData.CreateCopy;

  3. 的内容。

答案 2 :(得分:2)

如果您的工作水平较低,并且不希望编译器为您提供帮助,那么您需要使用PChar-strings而不是常规字符串。