Jump to content
alogrep

Stringgrid objects problem

Recommended Posts

HI.

I have some stringgrids that use objects.

For most of them  the object is simply an integer (MySg.objects[c,r]:=Tobject(mynumber);;

A few use complext object that I declare and assign a Create/destroy consctructor/desctuctor.

Now when i try to delete an object of the "comples type" all works fine: the destructor takes care of it..

If i do 

if assigned(MySg.objects[c,r]) then
  MySg.objects[c,r].free

On the Integer type, I get an AV exception.

Perhaps the integer type object does not need to be freed.

But then how do I inpect if the object is of integer type or not?

MySG.objects[c,r].classname gives me a "not acessible" message.

Any helop, please?

 

Share this post


Link to post

What you are doing is very error prone, for the reasons you describe. If you are using low valued integers, you could inspect the value of the objects[x,y] and if the value is below some threshold, then do not free it.

 

One way of doing this is 

1. Make sure to set all objects[x,y] to zero

2. if setting it to an integer value, set it to the negative of the integer you want. Make sure to when using the value to negate it again

3. If setting to an object, store the pointer as a positive integer

 

then, when freeing, only free where objects[x,y] is a positive value.  I think that will work for 32 and 64 bit until you have set your 32 bit app to specifically use memory above 2GB block. 

 

 

Share this post


Link to post
5 hours ago, alogrep said:

Perhaps the integer type object does not need to be freed.

Correct.

5 hours ago, alogrep said:

But then how do I inpect if the object is of integer type or not?

You can't. So, either store all objects only, or all integers only. Don't mix types. But, if you must, then you'll need to either wrap the integers inside of objects, or add an extra header in front of each value to identify its type, etc.

  • Like 2

Share this post


Link to post

This strikes me as being a classic use case for inheritence. Define a base class of a type ObjectToStoreInStringGrid and then derive each of the types you need to store from this base class. 

Share this post


Link to post
On 5/12/2025 at 4:18 PM, Dave Novo said:

If you are using low valued integers, you could inspect the value of the objects[x,y] and if the value is below some threshold, then do not free it.

Another option might be to use tagged pointers.

 

Normally, objects are aligned in memory in such a way that certain bits in object pointers are always zero, so those bits can be repurposed if you are careful.

 

For instance, if you limit your integer values to 31 bits (x86) or 63 bits (x64), you can use an unused bit in an object pointer to flag whether the pointer holds an integer value vs an object address, and just mask off the bit when extracting the value.

 

For example:

// this assumes objects are never stored at an odd-numbered memory address..

var intValue: Integer := ...;
Objects[c,r] := TObject((NativeUInt(intValue) shl 1) or $1);
...
var objValue: TObject := ...;
Objects[c,r] := objValue;
...
if (NativeUInt(Objects[c,r]) and $1) <> 0 then
begin
  // is an integer...
  var intValue := Integer(NativeUInt(Objects[c,r]) shr 1);
  ...
end
else
begin
  // is an object...
  var objValue := Objects[c,r];
  ...
end;
...
if (NativeUInt(Objects[c,r]) and $1) = 0 then
  Objects[c,r].Free;

 

Edited by Remy Lebeau
  • Like 1

Share this post


Link to post

Thank you all.

I came up with another solution, wich seems to work

The objects are either integer (very low, from 1-8)) or a typed (defined) object.

 

So I do this:

s:='';
try
  s:=objects[c,r].classname;  // only the integer objects do not have a classname
except
end;
if s<> '' then
  objects[c,r].free

Anybody sees some unseen problem with this?

Share this post


Link to post

That is a very dangerous approach. Don't do it that way. First, there is no guarantee that accessing the ClassName on an invalid object will raise an exception. And second, reading from invalid memory may cause other side effects (ie, page faults, etc).

 

Since your integers are very small, then you could simply look for integers first, and treat higher values as objects since they should never reside at such low memory addresses, eg:

const
  MaxObjIntValue = 8;
...  
var value := NativeInt(Objects[c,r]);
if (value >= 0) and (value <= MaxObjIntValue) then
begin
  // is an integer, use value as needed...
end
else
begin
  // is an object, use TObject(value) as needed...
end
...
if NativeInt(Objects[c,r]) > MaxObjIntValue then
  Objects[c,r].Free;

 

Edited by Remy Lebeau

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

×