2017-08-30 25 views
7

而不是使用geneirc 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;在类的构造我里面被声明为private我正在设定它的长度。


我已经阅读了关于docwiki的动态数组参考计数,所以我不必担心他们的一生。可以肯定,我写过:

constructor TEuclidMod.Create; 
begin 

SetLength(vals, 3); 

end; 

destructor TEuclidMod.Destroy; 
begin 

vals := nil; 
inherited; 

end; 

到目前为止,这应该没问题; vals属于这个类,我释放它对类的破坏。那么tmpArr

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

我想我是安全的,因为它是一个函数,它返回一个TSolution,因此ref的数量应该总是至少为1。确切吗?基本上:即使它是本地的,它是否正确返回?

但是从我SO发现,在这种情况下

procedure test; 
var a: TSolution; 
begin 

SetLength(a, 7); 
//do something 

end; 

a当程序超出范围总是释放!

+4

你可以沟渠tmpArr。不要直接声明它并使用Result。也毫无意义地将vals设置为无析构函数。无论如何,le destructor是这样做的,没有意义的做两次。 –

+4

使用'TArray '也更有意义,因为它具有更灵活的类型兼容性。和SetLength(vals,3);自从您稍后覆盖val之后,完全被浪费掉了。你有很大的理解,你不知道的赤字。 –

+2

说了这一切,你根本不应该使用动态数组。它应该是具有三个字段的记录,或者可以是长度为3的非动态数组。我认为一个记录是正确的选择。然后你可以命名这些字段。 –

回答

7

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

但是当我返回结果:= tmpArr不会被删除(tmpArr),因为函数超出了作用域?

哦,不,因为你已经通过将其分配给Result和,据推测,呼叫者也反过来结果赋给一个新的变量返回的数组。引用计数自然会保持至少一个,除非调用者也不将函数结果赋值给新变量。

+0

谢谢! :)所以,因为我怀疑裁判计数总是> = 1,所以它不会死? –

+1

@EmmaRossignoli如果你有一个变量中的数组引用,那么,是的,它必须仍然有一个大于零的引用计数。 –

+2

为了完整性,动态数组是引用计数的,但不要像'string'类型那样遵循CopyOnWrite(COW)模式。如果您修改数组中的一个项目,则每个将被复制的实例都将被修改,而对于'string'值,当您修改其中的'char'时,将会分配并复制一个新的'string'实例。 –