Forum > Beginners

Is it safe to store the address of a dynamic array element

(1/1)

Nimral:
This night I was plagued by a nightmare. I have used a structure like this to store a bunch of records:


--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---type  PPayload = ^TPayload;   TPayload = record    ID: integer;    Name: string[50];  end;  TArrPayload = array of TPayload; var  ArrPayload: TArrPayload; 
Later on I store the address of each element of the array as a pointer in a Virtual Treeview, and finally the tree captions are read from the array by the VirtualStringTree code.


--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---  for i := low(ArrPayload) to high(ArrPayload) do  begin    VirtualStringTree1.AddChild(nil, @ArrPayload[i]);  end;  ---   assert(assigned(Node), 'VirtualStringTree1GetText: Node not assigned');  // retrieve the address of the record  p := PPayload(Sender.GetNodeData(Node)^);  CellText := p^.Name;   
Tonight it came to me that I dimly remember having read that dynamic arrays are stored in a consecutive memory block, so when I add elements it might happen that the whole array needs to be relocated to a different memory block large enough to hold the whole array.

Is this correct? Do I have to expect that the VST breaks as I add array elements, because at some point the array gets moved to a larger memory block, invalidating all the stored pointers?

Thnx, Armin.

wp:

--- Quote from: Nimral on May 07, 2021, 08:50:16 am ---Do I have to expect that the VST breaks as I add array elements, because at some point the array gets moved to a larger memory block, invalidating all the stored pointers?

--- End quote ---
I did not test it, but I think so. I'd use a TList or similar rather than an array to store the items - see attachment.

MarkMLl:
In the general case, i.e. considering multiple languages and architectures, no.

It's safe to store a reference that you've been given explicitly and is documented as safe, like the reference that transparently refers to an object or an entire string or dynamic array, or to storage space that you've requested on the heap (which won't be moved or resized unless you request that).

It's not safe to store an address that you've finagled out of the runtimes, such as the address of one specific dynamic array element or one specific character in a string, because changes in the size of a dynamic array etc. might demand that its elements are moved.

If changes to the size of a dynamic array or string do not (ever) result in its elements being moved, then its storage must be fragmented... hence you can't rely on pointer arithmetic.

Assume that somebody designing a collection object (list, dictionary etc.) is aware of the pitfalls, and stores reference[index] of something he's looking at rather than address.

MarkMLl

Martin_fr:

--- Quote from: wp on May 07, 2021, 10:26:04 am ---
--- Quote from: Nimral on May 07, 2021, 08:50:16 am ---Do I have to expect that the VST breaks as I add array elements, because at some point the array gets moved to a larger memory block, invalidating all the stored pointers?

--- End quote ---
I did not test it, but I think so. I'd use a TList or similar rather than an array to store the items - see attachment.

--- End quote ---

TList also re-allocates it's memory. Not on every add, but eventually.
If you know the upper max bound, you can set the capacity first. But then you can pre-alloc your dyn array too.

If you need to keep track of your items, allocate them one by one with GetMem or New, and either:
- add their address to a list/array
- create a linked list

egsuh:

--- Quote --- Do I have to expect that the VST breaks as I add array elements, because at some point the array gets moved to a larger memory block, invalidating all the stored pointers?
--- End quote ---

I guess this may happen.  I do not know how VST operates, but

          VST.AddChild(parentnode, pointer); 

seems to allocate memory block (using GetMem (resultnode, recordsize))  if pointer is not defined, but if pointer is defined then it just stores the address internally.

In this kind of structure, the default is that you do not keep the record data yourself (ArrPayLoad in your case). You find a node in someway, and just retrieve the data in it. But sometimes it is necessary to maintain the data outside VST.

So I recommend you to keep array of pointers to record, not record data themselves, as I have shown in another thread. In this way, even though the physical address of ArrPPayLoad (which is array of PPayLoad) is changed, the address of records stored in the ArrPPayLoad and VST themselves are not changed.

Hope my comment is not offensive to you... I'm answering based on assumptions and more than you asked.

Navigation

[0] Message Index

Go to full version