Strings in Delphi (continued)

It seems the more you look, the more you find. There are a few interesting points in how strings are handled in Delphi; I’ve talked before about the particularities of String type in Delphi, so I’ll not touch that subject in this post. What I’m interested in, now, is to show how a particular case is handled: constant strings (literals).

Consider this example:

var
  S : String;
begin
  S := 'A Constant String';
  WriteLn('S ref count: ', StringRefCount(S));
  ReadLn;
end.

This code will show the expected “S ref count: 1” text in the console. Now, consider this code:

procedure Test();
var
  S : String;
begin
  S := 'A Constant String';
  WriteLn('S ref count: ', StringRefCount(S));
  ReadLn;
end;

begin
  Test();
end;

This code will show an interesting result: “”S ref count: -1”. So why is the string in the first example returning a reference count of 1 and the one in the second a -1? I presume that the reason is to prevent the RTL from disposing the literals on exit from a function. If the literal would have a RefCount of 1 it would be disposed which is obviously wrong. So a special case of -1 will prevent any of the auto-inserted function calls to do anything destructive on the literal strings. Considering that the main program entry point will still dispose anything at exit there is no need to use -1 to prevent it.

An interesting side-effect of that is that you can make your strings “never-to-expire”:

procedure ConstString(var S : String);
var
  P : ^Integer;
begin
  UniqueString(S);

  P := Pointer(S);
  Dec(P, 2);
  P^ := -1;
end;

This function will set the reference count to -1 thus preventing the RTL from disposing the string ever. The UniqueString call is required to ensure that we only “make a literal” out of the passed reference and not the other strings pointing to the same memory.