在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,这仍然是一个问题 - 还是有一种常见的方法来处理这个问题?
答案 0 :(得分:9)
自我分配在Delphi中很少见,这就是为什么它不常检查的原因。由于必须在堆上分配类实例,并且赋值运算符在类中不可覆盖,因此必须明确地从一个对象到另一个对象的赋值,例如通过TPersistent.Assign()
。大多数Delphi用户都了解这一点,并且不会编写会自动或以其他方式将对象分配给自身的代码。
自我赋值在C ++中更常见,特别是因为它在某些情况下实际上可以由编译器本身生成。赋值运算符是可重载的。因此,在C ++中进行自我分配检查更有意义。
答案 1 :(得分:4)
没什么好说的。您可以通过以下方式之一处理它:
Assign
。Assign
的实施中添加保护。如果源和目标是相同的,你再也不做任何事。整个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
是特定于设计实现的,在某些情况下会产生令人惊讶的结果。