【问题标题】:Two records sharing the same values?两条记录共享相同的值?
【发布时间】:2014-02-26 07:28:08
【问题描述】:

我向another question 询问了有关在运算符中使用记录的问题。在测试过程中,我发现了一个异常情况,两个此类实例似乎共享相同的内存。

记录有一个整数数组...

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

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

【问题讨论】:

  • PS - 我最初的问题中有一个错字,它以“A问...”开头,我想这与ReferQuestion(aAsked: TAskedQuestion);之类的东西有关

标签: arrays delphi delphi-xe2 record


【解决方案1】:

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

documentation 涵盖了这个:

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

要为此建立一个心智模型,动态数组的 this 作为 引用,其方式与类和接口相同。这与简单类型(整数、双精度等)、字符串、记录等形成对比。

处理这种情况的标准方法如下:

  1. 将动态数组设为私有。
  2. 通过属性公开数组的内容。
  3. 在元素设置器中,确保对动态数组的引用是唯一的。

最后一步是棘手的​​部分。通过调用 SetLength 使动态数组引用唯一:

SetLength(arr, Length(arr));

SetLength 做出的一个承诺是,它总是会使其第一个参数是唯一的。

这具有实现写时复制的效果。据我所知,不可能实现分配时复制,因为编译器没有为您提供赋值运算符的挂钩。

所以答案是:

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

是你不能。您需要改用写时复制。

【讨论】:

  • 作为一个障碍,我使用了V2:= String(V1);
  • 我理解它发生的原因,但我该如何解决这个问题?
  • @Jerry 我明白了。由于必须在我的 Q10 上回答,所以速度很慢
  • 那个赋值运算符基本上就是我想要的:(即兴发挥最好的:-)
  • @Rudy 对于大型阵列,SetLength 方法更好,因为它更便宜。很多时候数组已经是唯一的,使用SetLength可以避免不必要的复制。
猜你喜欢
  • 2012-03-26
  • 1970-01-01
  • 2018-05-27
  • 2011-03-03
  • 1970-01-01
  • 1970-01-01
  • 2016-06-20
  • 2023-03-16
  • 2021-12-17
相关资源
最近更新 更多