【问题标题】:Delphi dynamic array reference countingDelphi动态数组引用计数
【发布时间】:2017-08-30 11:02:58
【问题描述】:

我决定使用而不是使用通用 TList<integer>

TSolutions = array of integer;

然后:

function TEuclidMod.gcdExtended(p, q: integer): TSolutions;
var tmpArr: TSolutions;
begin

 SetLength(tmpArr, 3);

 if (q = 0) then
  begin
   tmpArr[0] := p;
   tmpArr[1] := 1;
   tmpArr[2] := 0;
  end
 else
  begin
   vals := gcdExtended(q, modulo(p,q));
   tmpArr[0] := vals[0];
   tmpArr[1] := vals[2];
   tmpArr[2] := vals[1] - vals[2]*floor(p/q);
  end;

 Result := tmpArr;

end;

变量vals: TSolutions;在类中被声明为私有,在构造函数中我正在设置它的长度。


我在 docwiki 上读到动态数组是 ref 计数的,所以我不必担心它们的生命周期。可以肯定的是我已经写了:

constructor TEuclidMod.Create;
begin

 SetLength(vals, 3);

end;

destructor TEuclidMod.Destroy;
begin

 vals := nil;
 inherited;

end;

到目前为止,这应该没问题; vals 属于班级,我在班级销毁时将其释放。 tmpArr 呢?

我的功能正常工作。 tmpArr 是本地的,然后我调用 SetLength 并给他一个长度:如果我没记错的话,这是在堆上创建数组。但是当我返回 Result := tmpArr 时,由于函数超出范围,它不会被删除(tmpArr)吗?我不想返回一个悬空指针或其他东西!我需要确保它没有被释放。

我想我是安全的,因为它是一个函数,它返回一个 TSolution,因此引用计数至少应该始终为 1。准确吗?基本上:即使是本地的,是否正确返回?

但是根据我在 SO 上的发现,在这种情况下

procedure test;
var a: TSolution;
begin

 SetLength(a, 7);
 //do something

end;

当过程超出范围时,a 总是被释放!

【问题讨论】:

  • 你可以放弃 tmpArr。不要声明它并直接使用 Result 。在析构函数中将 vals 设置为 nil 也是毫无意义的。 le 析构函数无论如何都会这样做,没有必要重复两次。
  • 使用TArray<Integer> 也更有意义,因为它具有更灵活的类型兼容性。和 SetLength(vals, 3);完全浪费了,因为您稍后会覆盖 vals。你有相当的理解不足,你没有意识到。
  • 说了这么多,你根本不应该使用动态数组。它应该是具有三个字段的记录,或者可能是长度为 3 的非动态数组。我认为记录是正确的选择。然后你可以命名这些字段。
  • @DavidHeffernan 好的,谢谢您的建议!该函数只是一个重载,因为我想尝试动态数组方式(事实上我已经要求解决一个疑问)。我更喜欢的是过程 getSolutions(aList: TList);
  • @EmmaRossignoli TList<integer> 感觉像是这个应用程序的一个沉重的容器,特别是如果您不需要使用 TList 添加的任何功能或好处。就像大卫说的那样,记录可能是一个更好的容器 - 更轻,堆栈分配为局部变量,在分配时复制(这符合您在这里的使用模式)并且您可以获得命名字段的好处,这使您的代码更具可读性。

标签: delphi


【解决方案1】:

动态数组是引用计数的。不用担心它们的内存管理——只需使用它们;这就是引用计数的用途。您不必nil 析构函数中的类字段。当对象被销毁时,编译器将删除它们的引用计数。

但是当我返回 Result := tmpArr 时,它不会因为函数超出范围而被删除 (tmpArr) 吗?

嗯,不,因为您已经通过将数组分配给Result 来返回该数组,并且可能调用者还将结果依次分配给一个新变量。除非调用者没有将函数结果分配给新变量,否则引用计数自然会保持至少 1。

【讨论】:

  • 谢谢!! :) 所以我怀疑 ref 计数总是 >= 1 所以它不会死?
  • @EmmaRossignoli 如果您在变量中有对数组的引用,那么,是的,它的引用计数必须仍然大于零。
  • 为了完整起见,动态数组是引用计数的,但不要像 string 类型那样遵循 CopyOnWrite (COW) 模式。如果您修改数组中的一项,则每个复制的实例都将被修改,而对于 string 值,当您在其中修改 char 时,将分配并复制一个新的 string 实例。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-05-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多