views:

267

answers:

3

Delphi uses reference counting with strings.

Do this mean that there is only one memory allocation for '1234567890' and all a,b,c,d, e and f.s reference to it?

 type  
   TFoo = class
    s: string;
   end;

  const 
    a = '1234567890';
    b = a;
    c : string = a;

  var
    d: string;
    e: string;
    f: TFoo;

  function GetStr1(const s: string): string;
  begin
   Result := s;
  end;

  function GetStr2(s: string): string;
  begin
   Result := s;
  end;

  begin
   d := GetStr1(b);
   e := GetStr2(c);
   f := TFoo.Create;
   f.s := a;
  end;
+5  A: 

yep, the strings are ref counted, a copy is created only when the contents are modified through a variable (copy on write semantics), more info here:

http://www.codexterity.com/delphistrings.htm

Good hint. So smart Delphi does not lose the refence when function returns a string.
pKarelian
http://www.codexterity.com/delphistrings.htm "WideString behaves exactly like AnsiString; it is automatically-managed, null-terminated and *reference-counted*" -> WideString's are NOT reference-counted!
kibab
+6  A: 

Small addition to the answer by jxac:

A copy will also be created when UniqueString() is called in code, when a character in the string is accessed by [], and when the string is typecasted to PChar. This happens even when the PChar and the string element will only ever be read.

It's important to know how to force a unique string from a potentially shared one, because there are Windows API functions that must not be called with a read-only char pointer, which a PChar to a string constant is. In that case the constant needs to be copied to a variable first, so casting it will return a PChar pointing to writable memory.

mghie
Yes. I noticed that when I called dll function with PChar parameter that returns data :-(
pKarelian
+9  A: 

Yes, there's only one allocation in your specific example. If you had used UniqueString, as mghie says, or if you had built the string dynamically, then you end up with a new string allocation even if the string contents are the same as some other string.

However, an interesting fact about your specific example: there is actually no memory "allocated" for the string '1234567890' at all. The data for string constants is stored in the executable image on disk, and is paged in by the OS when the code accesses it. It takes up memory address space, as part of the entire executable module's in-memory mapping, but since it is backed by the original executable on disk, it doesn't form part of the process's committed memory and won't need backing in the page file.

For example, this program will report an access violation on run:

{$apptype console}
uses SysUtils;

const
  s = '1234567890';
procedure Change(const r: string);
var
  p: PChar;
begin
  p := PChar(r);
  p^ := 'x';
end;

begin
  try
    Change(s);
  except
    on e: Exception do
      Writeln(e.Message);
  end;
end.
Barry Kelly
Intresting. We must be careful when using pointers.
pKarelian
If I declare const s : string = '1234567890';access violation is not raised? (I can't test it now)
pKarelian