两条记录共享相同的值?

时间:2014-02-26 07:28:09

标签: arrays delphi delphi-xe2 record

我问another question关于使用运营商的记录。在测试期间,我发现了一个异常现象,这种类型的两个实例似乎共享相同的内存。

该记录有一个Integer数组......

type
  TVersion = record
    Values: array of Integer;
    function Count: Integer;
    class operator implicit(aVersion: TVersion): String;
    class operator implicit(aVersion: String): TVersion;
  end;

class operator TVersion.implicit(aVersion: TVersion): String;
var
  X: Integer;
begin
  Result:= '';
  for X := 0 to Length(aVersion.Values)-1 do begin
    if X > 0 then Result:= Result + '.';
    Result:= Result + IntToStr(aVersion.Values[X]);
  end;
end;

class operator TVersion.implicit(aVersion: String): TVersion;
var
  S, T: String;
  I: Integer;
begin
  S:= aVersion + '.';
  SetLength(Result.Values, 0);
  while Length(S) > 0 do begin
    I:= Pos('.', S);
    T:= Copy(S, 1, I-1);
    Delete(S, 1, I);
    SetLength(Result.Values, Length(Result.Values)+1);
    Result.Values[Length(Result.Values)-1]:= StrToIntDef(T, 0);
  end;
end;

function TVersion.Count: Integer;
begin
  Result:= Length(Values);
end;

现在我尝试实现这个......

var
  V1, V2: TVersion;
begin
  V1:= '1.2.3.4';
  V2:= V1;
  ShowMessage(V1);
  ShowMessage(V2);
  V2.Values[2]:= 8;
  ShowMessage(V1);
  ShowMessage(V2);
end;

我希望V2 1.2.8.4V1保持1.2.3.4。但是,V1也会更改为1.2.8.4

如何在分配这些记录时保持这些记录的独立性?

1 个答案:

答案 0 :(得分:4)

此行为是设计使然。动态数组变量是指针。分配动态数组变量时,需要复制指针并增加引用计数。当然,当您指定包含动态数组的复合结构时,也会发生这种情况。

documentation涵盖了这个:

  

如果X和Y是相同动态数组类型的变量,则X:= Y将X指向与Y相同的数组。(在执行此操作之前无需为X分配内存。)与字符串和静态不同数组,写时复制不用于动态数组,因此它们在写入之前不会自动复制。

为了得到一个心理模型,动态数组的这个引用的方式与类和接口相同。这与简单类型(整数,双重等),字符串,记录等形成对比。

处理此问题的标准方法如下:

  1. 将动态数组设为私有。
  2. 通过属性公开数组的内容。
  3. 在元素设置器中,确保对动态数组的引用是唯一的。
  4. 最后一步是棘手的​​部分。通过调用SetLength

    使动态数组引用唯一
    SetLength(arr, Length(arr));
    

    SetLength所做的一个承诺是它总是使它的第一个参数是唯一的。

    这具有实现写时复制的效果。据我所知,不可能实现copy-on-assign,因为编译器不会为赋值运算符提供挂钩。

    答案是:

      

    如何在分配这些记录时保持这些记录的独立性?

    是你不能。您需要使用copy-on-write。