2

I am using this code to check whether TStringList is created or not:

procedure TForm1.Button1Click(Sender: TObject);
var

  sVariable : TStringList;
begin
   if not Assigned(sVariable) then
   sVariable:= TStringList.Create;
end; 

But the condition is False always, why does that happen? How do I check if TStringList object is created or not?

P.s. I am aware of a similar question asked, I tried the solution posted in that one, but it is not working for me.

menjaraz
  • 7,551
  • 4
  • 41
  • 81
CyprUS
  • 4,159
  • 9
  • 48
  • 93
  • can you tell us where sVariable is being declared – Shirish11 Nov 04 '11 at 10:35
  • @Shirish11 : I updated my answer , it is a local variable – CyprUS Nov 04 '11 at 10:38
  • The problem is probably not in the code you quoted but in how it gets to the result. Does this code sit inside of a function? Does the sVariable come in as a parameter? How do you create the object before? If you provide with more details about these, that probably will get closer to the solution. – Attila Fulop Nov 04 '11 at 10:32
  • Please provide a link to the "similar question" you saw. If the solution didn't work for you, someone might need to update it. – Rob Kennedy Nov 04 '11 at 13:17
  • 1
    Because an answer is to always solve compiler warnings and hints yourself, namely `W1036 Variable 'sVariable' might not have been initialized` – Premature Optimization Nov 04 '11 at 14:38
  • Checking if a local variable is created is....pointless. The code as posted above is non-sensical. In the above case, the way to know if the TStringList has been created is to read the code and see. In other words, you *always* have to manually create a TStringList that is a local variable. You never don't have to create it. – Nick Hodges Nov 04 '11 at 20:47
  • The way you have your code now, it will never work. Make sVariable global and it will work. – Gabriel Mar 02 '16 at 21:35

5 Answers5

15

When you allocate an object reference on the stack, it is filled with random values (i.e. the previous values on the stack - which may be nil in some border cases). This is by design.

In order to check if the variable is initialized, you'll have first to set it manually to nil. This is a very fast assignment.

A typical code pattern may be:

procedure TForm1.Button1Click(Sender: TObject);
var
  sVariable : TStringList;
begin
  sVariable := nil; // initialize explicitely
  try
    (...) // in this hidden part sVariable may be instantiated
    if not Assigned(sVariable) then // instantiate if not already done
      sVariable:= TStringList.Create; 
    (...)
  finally
    sVariable.Free; // will do nothing if sVariable=nil
  end;
end; 

Note that in the above code, I've included a (mandatory IMHO) try...finally block to release the memory. If sVariable was not allocated, it is still nil, and in this case sVariable.Free will do nothing. It is an usual best practice pattern in Delphi.

Arnaud Bouchez
  • 42,305
  • 3
  • 71
  • 159
8

You can assume that the object is not created and the variable initialized with garbage (because it's a local variable). Just create your StringList and everything is fine.

Community
  • 1
  • 1
Heinrich Ulbricht
  • 10,064
  • 4
  • 54
  • 85
  • You do not understand my question, How do i check if a Stringlist is created or not ( without garbage values) – CyprUS Nov 04 '11 at 10:41
  • 8
    `if Assigned(sVariable)` normally is the right way to do it. But in your case checking is irrelevant. You _know_ that the list hasn't been created. Your local variable initially contains garbage which means the variable points to some memory location which in fact doesn't contain a TStringList. The key is: the variable is not nil, but contains no valid TStringList either. You cannot check this. You know this ;) – Heinrich Ulbricht Nov 04 '11 at 10:45
  • http://stackoverflow.com/questions/8598408/how-to-detect-dangling-pointers-if-assigned-cant-do-it – Jerry Dodge Dec 06 '14 at 14:39
7

First of all: the code you published makes no sense. Because sVariable is a local variable it is always uninitialized. But unlike to variables in object-scope, uninitialized doesn't implies that it is nil. Delphi won't set local variables to nil. So sVariable contains a completly random value. Assigned() only checks if the value is nil - not if it points to a valid instance of an object.

Michael
  • 858
  • 1
  • 5
  • 11
  • it wasn't meant that harsh - it just sounds so because of my poor english. – Michael Nov 04 '11 at 10:57
  • 2
    *Delphi won't set local variables to nil* is not 100% true: it does initialize all reference-counted values, i.e. `string, variant, array of, interface` kind of local variables, which are voided. It won't set local reference to classes, like in the OP code. – Arnaud Bouchez Nov 04 '11 at 18:12
  • "completely random value" is also wrong ;) Actually it's pretty deterministic, it depends on what was on the unused part of the stack before that function was called, and it depends on what was called before. IMHO the correct term is that on entry a local variable value is "undefined", because but some exceptions Delphi doesn't set them to any "defined" value. –  Nov 04 '11 at 19:34
3

You can do this directly because it's a local variable

procedure TForm1.Button1Click(Sender: TObject);
var
  sVariable : TStringList;
begin
  sVariable:= TStringList.Create;
end;
TLama
  • 75,147
  • 17
  • 214
  • 392
Shirish11
  • 1,587
  • 5
  • 17
  • 39
  • I don't understand why 'because it's a local variable' ? What do you do with global ones ?? – philnext Nov 04 '11 at 14:26
  • 2
    @philnext: Because globals are automatically set with `nil`. Locals doesn't - it's simply have garbage there (maybe even nil, but don't count on it). – Fabricio Araujo Nov 04 '11 at 15:26
3

After your update of the question, what I see, seems to be quite normal.

When you define an object variable (sVariable) it doesn't get initialized, that you have to do with the Create constructor. In this case you don't even have to check for whether it exists or not.

procedure TForm1.Button1Click(Sender: TObject);
var
  sVariable : TStringList;
begin
   sVariable:= TStringList.Create;
   //Work with the stringlist e.g add items:
   sVariable.Add('Blah');
   //Make sure it finally gets freed 
   sVariable.Free;
end; 
Attila Fulop
  • 6,861
  • 2
  • 44
  • 50