Delphi中的自我分配

时间:2014-04-22 11:02:22

标签: delphi vcl

在C ++中,赋值运算符中有一个常见的习惯用法,你必须避免因将对象复制到自身而引起的问题。

http://www.parashift.com/c++-faq/self-assignment-why.html

但是,在Delphi VCL中(至少在D2010中),这似乎并没有得到很好的处理。

例如,以下函数将清除传递给它的TStringList

procedure foo(var strings:TStringList)
begin 
  strings.Assign(strings);
end;

对于更高版本的Delphi,这仍然是一个问题 - 还是有一种常见的方法来处理这个问题?

3 个答案:

答案 0 :(得分:9)

自我分配在Delphi中很少见,这就是为什么它不常检查的原因。由于必须在堆上分配类实例,并且赋值运算符在类中不可覆盖,因此必须明确地从一个对象到另一个对象的赋值,例如通过TPersistent.Assign()。大多数Delphi用户都了解这一点,并且不会编写会自动或以其他方式将对象分配给自身的代码。

自我赋值在C ++中更常见,特别是因为它在某些情况下实际上可以由编译器本身生成。赋值运算符是可重载的。因此,在C ++中进行自我分配检查更有意义。

答案 1 :(得分:4)

没什么好说的。您可以通过以下方式之一处理它:

  1. 在呼叫站点添加保护。当源和目标相同时,不要调用Assign
  2. Assign的实施中添加保护。如果源和目标是相同的,你再也不做任何事。
  3. 整个RTL / VCL的设计选择是前者。我不知道RTL / VCL中Assign的任何实现,它检查引用相同对象的源和目标。这意味着调用者有责任执行检查。

    是的,您可以选择自己类型的选项2。但是现在你要做的设计决定与RTL / VCL中的设计决定相冲突。沿着那条路走下去,想想很久很久。除非有充分理由否则你应该遵循框架设定的先例。

    我认为RTL / VCL的设计者选择了选项1,因为要么他们没有考虑问题,要么他们考虑了这个问题,并且认为在Assign的每个实现中添加检查的理由太少了。

答案 2 :(得分:2)

错误是假设Assign与您熟悉的语言中的赋值运算符的含义相同。事实并非如此。

System.Classes.TPersistent.Assign的{​​{1}}说明如下:

  

复制另一个类似对象的内容。

     

调用Assign复制一个对象的属性或其他属性。

接着具体说明TPersistent.Assign并不等同于C ++赋值运算符重载。

TPersistent.Assign是特定于设计实现的,在某些情况下会产生令人惊讶的结果。