Jump to content

Recommended Posts

why this IfThen inline function gives me Object is Allocated in memory !!
---

type
  TMainView = class(TForm)
    Label1: TLabel;
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  MainView: TMainView;

implementation

type
  TMyClass = class
  private
//    fValue: string;
    class var ClassValue: string;
    function GetValue: string;
    procedure SetValue(const aValue: string);
  public
    property Value: string Read GetValue write SetValue;
  end;
  
{ TMyClass }

function TMyClass.GetValue: string;
begin
  Result := ClassValue;
end;

procedure TMyClass.SetValue(const aValue: string);
begin
  ClassValue := aValue;
end; 
  
{ TMainView } 
  

function IsAllocated(aObj: TMyClass): Boolean;
begin
  Result := Assigned(aObj);

  case Result of
    True: aObj.Value := 'the OBJECT Is Allocated ..';
    False: aObj.Value := 'Not Allocated Yet !!';
  end;
end;

procedure TMainView.FormCreate(Sender: TObject);
var
  LObj: TMyClass;
begin
//  LObj := nil;
//  LObj := TMyClass.Create;

  Label1.Caption := IfThen(IsAllocated(LObj),
    LObj.Value, LObj.Value);

end;

link to github test project here

 

Result_NotLogic.jpg

Share this post


Link to post

LObj is local variable and it is not initialized. That means it will hold some random value (garbage). This is why it can show that object is allocated when it is actually not. You need to initialize it (to nil, or assign some object instance to it) before you can call your function.

  • Like 1

Share this post


Link to post

Because LObj is not initialized to nil; therefore, it gets whatever happens to be in memory. Assigned() simply checks to see if the pointer is 0; when I ran it in Delphi 12.1, and put a break-point at the label assignment, LObj was -1 ($FFFFFFFF).

  • Like 1

Share this post


Link to post

When you compiled, you likely got the following warning:

[dcc32 Warning] Main.View.pas(54): W1036 Variable 'LObj' might not have been initialized

 

You should always take special notice to eliminate warnings in your code.

  • Like 3

Share this post


Link to post
24 minutes ago, Dalija Prasnikar said:

LObj is local variable and it is not initialized. That means it will hold some random value (garbage). This is why it can show that object is allocated when it is actually not. You need to initialize it (to nil, or assign some object instance to it) before you can call your function.

Do random values only occur for local variables?
Why does uninitialized memory sometimes contain garbage values, especially when an object hasn't been allocated yet?

LObj is just a variable that will reference the object once TMyClass creates it.
Does TMyClass automatically assign anything to LObj just by declaring it like this?

var
  LObj: TMyClass;

 

Share this post


Link to post
4 minutes ago, bravesofts said:

Do random values only occur for local variables?

Not. The best practice is to initialize to nil if you need this.

7 minutes ago, bravesofts said:

Why does uninitialized memory sometimes contain garbage values, especially when an object hasn't been allocated yet? 

Because there was something before and that memory was deallocated.

It doesn't have anything with object allocation. You can allocate the memory for an object and you variable will remain as it was.

var 
  LObj: TObject;
begin
  TMyClass.Create;
  //LObj is not changed and will contain garbage

 

10 minutes ago, bravesofts said:

LObj is just a variable that will reference the object once TMyClass creates it.

Only if you pass the value of the object to the variable:

LObj := TMyClass.Create;

 

13 minutes ago, bravesofts said:

Does TMyClass automatically assign anything to LObj just by declaring it like this? 


var
  LObj: TMyClass;

  

Not. Declaration will only allocate the memory for the variable (a typed pointer in this case) and that memory will contain garbage.

  • Like 1

Share this post


Link to post
3 minutes ago, Cristian Peța said:

Not. Declaration will only allocate the memory for the variable (a typed pointer in this case) and that memory will contain garbage.

So, the heap might contain some garbage data, and when we declare a variable, the pointer may refer to something that isn’t related to our program at all. Does this happen only in Windows?

Share this post


Link to post
13 minutes ago, bravesofts said:

LObj is just a variable that will reference the object once TMyClass creates it.

There are two allocations for memory you're dealing with:

  1. LObj is a pointer to an object. That pointer takes up space in memory and is allocated in your VAR declaration section as soon as that procedure is called. If it's not specifically initialized with either nil or a pointer to an actual object, the value of that pointer will contain whatever happened to be in that memory location.
  2. The second memory allocation happens when the statement LObj := TMyClass.Create; is called. That allocates memory for the object type TMyClass and the pointer to that memory space is stored in the LObj pointer variable.

So when you say "LObj is just a variable..." you're right but you might be forgetting what that means: it's a variable at a memory location and in this case, it's a pointer variable that doesn't yet know what it's pointing at.


Another way to look at it is if you declared this in your VAR section:

var
  X: Integer

X is a variable just like LObj is in that it's allocated when the procedure is called and similarly, if you don't assign X a value, you'll end up with whatever value happens to be in that memory space. Can you imagine testing the value of X without first assigning a number to it?

  • Like 3

Share this post


Link to post
Posted (edited)

 

12 minutes ago, bravesofts said:

So, the heap might contain some garbage data, and when we declare a variable, the pointer may refer to something that isn’t related to our program at all. Does this happen only in Windows?

It doesn't work like that.

 

LObj is reference type. That means it consists of two parts. LObj variable itself is merely a pointer (address) that will point to the object instance when it is allocated on a heap. All local variables are allocated on stack, not heap. So when you declare local variable the memory for the pointer is automatically allocated on stack when FormCreate is called. Stack memory is not automatically cleared, so whatever values were there, they will remain. Only managed types local variables will be automatically initialized.  

 

When you create object and assign it to that variable then created instance will be allocated on a heap and address of that memory location will be stored in LObj variable. 

 

This behavior is same on all platforms. However, until Delphi 10.4 Delphi mobile platforms had ARC compiler where objects were automatically managed and local object variables were automatically initialized on those platforms.

Edited by Dalija Prasnikar
  • Like 2
  • Thanks 1

Share this post


Link to post

i ask GPT for a good Example and gives me this:
 

procedure TMainView.Btn_1Click(Sender: TObject);
var
  LObj: TMyClass;  // Declare a local variable of reference type
begin
  // At this point, LObj is just a pointer, and it hasn't been assigned to any object yet.
  ShowMessage(IntToStr(Integer(LObj)));  // This may show some random (garbage) value

  LObj := TMyClass.Create;  // Now, LObj points to a new instance of TMyClass allocated on the heap.
  ShowMessage(IntToStr(Integer(LObj)));  // This will show the actual memory address of the object instance

  // When you’re done, free the object to avoid memory leaks.
  LObj.Free;
end;

Explanation

  1. LObj Declaration:

    • LObj is declared as a variable of type TMyClass. This is a reference type, which means LObj is just a pointer (an address) that will eventually point to an object instance.
  2. Memory Allocation:

    • LObj itself is a local variable, so it is allocated on the stack. However, the object instance that LObj will point to is allocated on the heap when you create it using TMyClass.Create.
  3. Garbage Value:

    • When LObj is declared, it hasn't been initialized to point to anything. The memory allocated on the stack for LObj might contain whatever data was there before, which is why ShowMessage(IntToStr(Integer(LObj))) might display a random (garbage) value. This is because stack memory isn't automatically cleared.
  4. Object Creation:

    • When you create a new instance of TMyClass with LObj := TMyClass.Create;, the memory for this instance is allocated on the heap. LObj now holds the memory address of this instance.
  5. Managed Types:

    • Only managed types (e.g., strings, dynamic arrays, interfaces) are automatically initialized to nil or equivalent values when declared. Since LObj is not a managed type, it can hold any value until you explicitly initialize it by creating an object.

Key Takeaways

  • Uninitialized Pointers: If you don't initialize a reference type variable (like LObj), it might contain a garbage value that points to an undefined memory location.
  • Memory Allocation: Local variables are allocated on the stack, but the actual object instances they point to are allocated on the heap.
  • Automatic Initialization: Only managed types are automatically initialized to nil or similar default values when declared.

This example illustrates the importance of initializing your reference variables to nil or creating an object before using them to avoid unexpected behavior.
----
I have a much clearer understanding of the entire process now. Thank you, everyone!

  • Like 2

Share this post


Link to post

A small correction for this GPT answer:

1 hour ago, bravesofts said:

LObj itself is a local variable, so it is allocated on the stack.

Not every local variable is allocated on the stack, so LObj could be on the stack, or due to optimization have a dedicated CPU register to use.

In other words, LObj is either on the stack or in a register, but the result will be the same, the stack might hold data (Value) previously been written (or zero if the stack is never being reached before at this depth), and a register will have a Value from the last usage being from this procedure/function or a previous one.

 

Delphi compiler is less optimized for this registers usage (optimization) for local variable then FPC and less than most other languages compilers, yet it does it sometimes.

  • Like 1

Share this post


Link to post
2 hours ago, bravesofts said:

i ask GPT for a good Example and gives me this:

I would suggest that you don't use ChatGPT or any other AI for writing or explaining the code. While it may give you correct results at times, quite often it will be completely wrong and you will have no idea whether what it said is correct or not.

  • Like 5

Share this post


Link to post
20 minutes ago, Dalija Prasnikar said:

While it may give you correct results at times, quite often it will be completely wrong and you will have no idea whether what it said is correct or not.

If you provide GPT with the correct results and all necessary information bits it needs,
it can produce a very good explanation in a very precise natural language, even if the original explanations were spelled too lazy or informal.
Especially in this category of natural language it works very well, to produce very precise desciptions of known facts and sources.

You are right, that you still need to check this output well, but that is always the case with todays AI.
The chance of AI hallucination is quite low, if you give it an already predefined, correct text pattern, that just needs to be summarized, re-formatted and completed.
In fact I have never seen any hallucination from at least ChatGPT 4, when it comes to these tasks and proper input prompt.
 

  • Like 1

Share this post


Link to post
1 hour ago, Rollo62 said:

it can produce a very good explanation in a very precise natural language, even if the original explanations were spelled too lazy or informal.
Especially in this category of natural language it works very well, to produce very precise desciptions of known facts and sources.

Er... no. It does not matter how correct is the input, the output can still be outmost garbage when it comes to the correctness, it will just sound nice.

 

Also, if you don't know whether some statement is correct or not how can you verify the output. For instance AI can say "Local variables are automatically initialized" and "Local variables are not automatically initialized" If you don't know which of those statements is true, you will not be in position to verify. You cannot even check with code, because local variable can accidentally occupy memory that was zero at the time, so it may seem like the first statement is true, while it is not.

 

It does not matter how often it is correct (the best AI will be wrong in over 20% of responses, which is far from insignificant), it is about inability of a person who does not know something to determine whether response is correct or not. Even merely translating and rewording of correct content can result with incorrect output. 

 

Some examples how AI can lie to you: https://github.com/mdn/yari/issues/9208 and MS copilot demonstration video around 38 minutes.

 

 

  • Like 3

Share this post


Link to post
Posted (edited)

Well, my reference is always the ChatGPT 4o, while all my experiments with M$ Copilot or Bing or whatever from Microsoft was never working acceptable for me.
Ok, I admit you can have bad AI and better AI.
CGPT, Sonnet are quite acceptable in their latest incarnations, perhaps others too.
At least from my practical experience, the ChatGPT 4o output is very reliable for all sorts of tasks,
of course I try to help AI as best as I can by producing reasonable prompts.
In re-formatting it's much better than 20% failure rate, I would guess by gut feeling, I would say 2-5% failure in my workflows.
 

Edited by Rollo62
  • Like 1

Share this post


Link to post
1 hour ago, Dalija Prasnikar said:

For instance AI can say "Local variables are automatically initialized" and "Local variables are not automatically initialized" If you don't know which of those statements is true, you will not be in position to verify. You cannot even check with code, because local variable can accidentally occupy memory that was zero at the time, so it may seem like the first statement is true, while it is not. 

Assembler of that code will show the truth... but I think that someone that ask such things do not have ability to read assembler.

Share this post


Link to post
3 hours ago, Rollo62 said:

At least from my practical experience, the ChatGPT 4o output is very reliable for all sorts of tasks,
of course I try to help AI as best as I can by producing reasonable prompts

i agree with you @Rollo62   on this term, we should be the first to ask a good questions to get a good answers with best accuracy of the truth ..

5 hours ago, Rollo62 said:

The chance of AI hallucination is quite low, if you give it an already predefined, correct text pattern, that just needs to be summarized, re-formatted and completed.

By the way, the answer from ChatGPT above would have been impossible without the question being, in reality, the answer from the highly respected and dear-to-my-heart @Dalija Prasnikar. If you take a closer look at what ChatGPT provided above, you’ll notice that it did a wonderful job of summarize, re-format and complete ., and beautifully elaborating on the esteemed professor Dalija Prasnikar's response..

5 hours ago, Rollo62 said:

it can produce a very good explanation in a very precise natural language, even if the original explanations were spelled too lazy or informal.

The above post from ChatGPT 4.o is the best proof of what you say.

---

finally , I want to thank you all once again for your amazing and enthusiastic contributions. Your accuracy in providing information has really helped me understand and sum up a journey that many people might still be struggling with. 

 

  • Like 1

Share this post


Link to post
2 hours ago, Cristian Peța said:

but I think that someone that ask such things do not have ability to read assembler

Did the tone of this conversation lean towards mockery or belittling the person asking the question, or am I mistaken?
--
In any case, thank you for the information.

Share this post


Link to post
2 hours ago, bravesofts said:
  5 hours ago, Cristian Peța said:

but I think that someone that ask such things do not have ability to read assembler

This remark applies in full measure to me :classic_laugh:

Share this post


Link to post
9 hours ago, Cristian Peța said:
10 hours ago, Dalija Prasnikar said:

For instance AI can say "Local variables are automatically initialized" and "Local variables are not automatically initialized" If you don't know which of those statements is true, you will not be in position to verify. You cannot even check with code, because local variable can accidentally occupy memory that was zero at the time, so it may seem like the first statement is true, while it is not. 

Assembler of that code will show the truth... but I think that someone that ask such things do not have ability to read assembler.

Disassembled code would reveal the code generated by the compiler. But it isn't going to reveal the contents of memory (registers, stack, or heap) prior to the code even executing. As Dalija points out, I could execute it once and the memory was zero at the time and execute it a thousand more times and the memory has values aside from zero.

  • Like 1

Share this post


Link to post
5 hours ago, bravesofts said:
9 hours ago, Cristian Peța said:

but I think that someone that ask such things do not have ability to read assembler

Did the tone of this conversation lean towards mockery or belittling the person asking the question, or am I mistaken?

You are mistaken. I've been coding for 43 years and I don't read assembler. I know what a *few* x86 instructions do. But not enough to look at a disassembled function and determine what the code does. At least, not without spending a LOT of time trying to figure it out. :classic_wink:

  • Like 1

Share this post


Link to post
Posted (edited)

@bravesofts Tell me, if you go to a restaurant and they don't use a dishwasher, but instead simply wipe off dishes that people use and then use them again, what do you get served a drink in? You'd call it a "dirty cup".

 

The cup or dish itself is there -- it's intact, it's complete, it's ready to go. But it's "dirty" -- its contents have not been set to "clean", initialized as it were, or NIL if it's an object.

 

A variable in Delphi is a pointer. The assumption is that it points to an object somewhere. The language requires you to set it to a known initial state -- that's called INITIALIZATION.

 

You can initialize it to either NIL or a valid pointer. Just leaving it uninitialized raises a compiler warning and usually leads to bugs if ignored.

 

Declaring a variable as an object allocates a pointer and you don't know until run-time if what it's pointing at is a valid object or not. If you're lucky it throws a memory error; if you're unlucky, it goes off into the weeds because the data appears valid and eventually crashes on something unrelated, sending you down a rabbit hole that's unrelated to the REAL error.

 

Your code is correct as far as Delphi's syntax and semantics go. Only it's not reflecting what you think it is. You're testing the contents of the pointer var itself, not the OBJECT.

 

There's a built-in function called Assigned(x) that you should be using, not your own method, IsAllocated, because all Delphi knows is if the reference is NIL or not. If it's not, then it assumes it's a pointer to a valid instance of said object. It has no way of knowing if it's allocated or not, or even if it's valid or not.

 

If your code NEVER INITIALIZES it, then local variables take on whatever value is in the memory allocated on the stack for that variable.

 

You need to INITIALIZE IT BEFORE USING IT. Usually, that means you say: myVar := NIL;

 

You can also say something like: myVar := TMyObject.Create();

 

In C++ you can specify initialization values for specific fields in the class IN THE DEFINITION so that when you DECLARE AN INSTANCE then those fields are AUTO-INITIALIZED. This is not possible in Delphi.

 

Declaring a variable for an object does not create an instance of it; the value of that pointer is not auto-initialized -- you have to do it yourself, usually by setting it to NIL.

 

 

 

Edited by David Schwartz
  • Like 1

Share this post


Link to post
11 hours ago, bravesofts said:

Did the tone of this conversation lean towards mockery or belittling the person asking the question, or am I mistaken?

I apologize, now that I read again was I wrote... but it was not my intention.

  • Like 1

Share this post


Link to post
5 hours ago, JonRobertson said:

Disassembled code would reveal the code generated by the compiler. But it isn't going to reveal the contents of memory (registers, stack, or heap) prior to the code even executing. As Dalija points out, I could execute it once and the memory was zero at the time and execute it a thousand more times and the memory has values aside from zero.

Compiler generated code can tell you if a variable is automatically initialized or not. I only wanted to point out that there is a method to check if an AI statement in this regard is true or not.

  • Like 1

Share this post


Link to post
9 hours ago, Cristian Peța said:

Compiler generated code can tell you if a variable is automatically initialized or not.

Ah, yes. My apologies. That is a valid point.

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×