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.