Question

In C++ there's a common idiom in assignment operators where you must avoid problems caused by copying an object to itself.

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

But, in Delphi VCL (at least in D2010) this doesn't seem to be handled well.

As an example, the following function will clear the TStringList passed to it!

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

Is this still an issue with later versions of Delphi - or is there a common way of handling the problem?

Was it helpful?

Solution

Self assignment is rare in Delphi, which is why it is not commonly checked for. Since class instances must be allocated on the heap, and the assignment operator is not overridable in classes, assignment from one object to another must be done explicitly, such as via TPersistent.Assign(). The majority of Delphi users understand that and do not write code that would assign an object to itself, accidentally or otherwise.

Self assignment is more common in C++, especially since it can actually be generated by the compiler itself in some cases. And the assignment operator is overloadable. So it makes more sense to do self assignment checks in C++.

OTHER TIPS

There's not much to say. You can deal with it in one of the following ways:

  1. Add protection at the call site. Refrain from calling Assign when source and destination are the same.
  2. Add protection in the implementation of Assign. Again you simply do nothing if source and destination are the same.

The design choice made throughout the RTL/VCL is the former. I'm not aware of any implementation of Assign in the RTL/VCL that checks for source and destination referring to the same object. Which means the onus is on you the caller to perform the checks.

Yes you could opt for option 2 in your own types. But now you'd be taking a design decision that clashes with that made in the RTL/VCL. Think long and hard before going down that route. Unless there are strong reasons to do otherwise you should always follow the precedent set by the framework.

I imagine that the designers of the RTL/VCL opted for option 1 because either they did not consider the issue, or they considered it and decided that it was too rare to justify adding checks to every implementation of Assign.

The mistake is to assume that Assign is supposed to mean the same thing as the assignment operator in your familiar language. It is not.

The documentation for System.Classes.TPersistent.Assign says the following:

Copies the contents of another similar object.

Call Assign to copy the properties or other attributes of one object from another.

It goes on to specifically say that TPersistent.Assign is not mean to be equivalent to the C++ assignment operator overload.

TPersistent.Assign is by design implementation specific and can have surprising results in some cases.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top