2009-06-04 65 views
3

我有一个包含动态数组的记录。当您将一个数组变量分配给另一个数组时,通常只分配指向该数组的指针是很正常的。这意味着当你这样做的时候,两个变量指向相同的数组,直到你改变其中一个变量的大小。因此,当我想将一个数组的单独副本分配给一个变量时,我使用Copy()函数。您是否可以重载Delphi记录的赋值运算符?

在这种情况下,然而,我的阵列是记录的字段:

TMyRec = record 
    Value: integer; 
    &Array: array of integer; 
    end; 

当我声明类型TMyRec的两个变量,然后分配一个到另一个时,“阵列”字段在两者的记录将指向内存中的相同地址。

为了解决诸如此类的问题,我决定重载赋值运算符如下:

TMyRec = record 
    Value: integer; 
    &Array: array of integer; 
public 
    class operator Implicit(Value: TMyRec): TMyRec; 
end; 

class operator TMyRec.Implicit(Value: TMyRec): TMyRec; 
begin 
    Result := Value; 
    Result.&Array := Copy(Value.&Array); 
end; 

如果这个工作,我就不必复制我的记录所有数组字段分配TMyRecord一个变量分别后到另一个。

这里是我做的:

var 
    Rec1, Rec2: TMyRec; 
begin 
    Rec1.Value := 10; 
    SetLength(Rec1.Array, 1); 

    //I expected the "Implicit" method to be invoked here (but it is not...) 
    Rec2 := Rec1; 

    //if I do that, the Rec1.Array[0] will also be changed to 1 - I don't want that to happen 
    Rec2.Array[0] := 1; 
end; 

有没有办法让我的运算符重载的工作,我希望它?事情是,我试图超载默认赋值运算符。这不可能吗?

+0

[是的,在某种程度上(https://stackoverflow.com/a/47320631/7579632),如果你愿意滥用语言。 – 2017-11-16 12:28:03

回答

7

您可以将数组放入实现接口的对象实例中,并在该记录内存储对该接口的引用。这样,当您尝试通过接口(并因此通过对象)分配给数组时,它可以检查其引用计数并有助于写入时复制语义。

或者,您可以使用类型不安全的技巧来找出数组的引用计数,并在写入之前手动复制,如果存在多个引用;但是如果动态数组实现发生了变化,那将不受支持并会中断。

I wrote up如何实现写入时复制数组结构,并将其包装在记录中。它被实现为一个泛型类型,但是没有任何东西阻止你使用具体的数组类型,它不会像一般泛型一样。

1

不要做简单的分配。为了可读性而去。做你自己喜欢的“RecCopy”过程:

procedure RecCopy(const AFrom, ATo : TMyRec); 
var 
    I : integer; 
begin 
    ATo.Value := AFrom.Value; 
    SetLength(ATo.Array, Length(AFrom.Array); 
    For I := 0 to Length(AFrom.Array)-1 do 
    ATo.Array[I] := AFrom.Array[I]; 
end; 

注意,您可以使用implmenting数组复制:-) 但你明白我的意思的更好的方法。

+0

糟糕 - 应该读取RecCopy(const AFrom:TMyRec; VAR ATo:TMyRec);抱歉! – 2009-06-05 08:44:20

3

可以使用TMyRec的指针:

pMyRec = ^TMyRec; 
TMyRec = record 
    Value: integer; 
    _Array: array of integer; 
public 
    class operator Implicit(Value: pMyRec): TMyRec; 
end; 

class operator TMyRec.Implicit(Value: pMyRec): TMyRec; 
begin 
    Result := Value^; 
    Result._Array := Copy(Value^._Array); 
end; 

procedure TForm1.Button1Click(Sender: TObject); 
var R1, R2 : TMyRec; 
begin 
    R1.Value := 1; 
    SetLength(R1._Array, 2); 
    R1._Array[0] := 1; 
    R1._Array[1] := 2; 

    R2 := @R1; 
    R2._Array[0] := 3; 
end;