Joylon,
Good point. But I dont think it applies here. Sizeof returns an
incorrect result... Its a compiler flaw.
Rohit
On 29/08/2011 8:10 p.m., Jolyon Smith wrote:
Having just looked up the references for New/GetMem it may not
actually be a question of amount of memory allocated after all, but
rather one of correct initialization of the allocated memory.
GetMem() does not initialize the allocated memory, New() does.
This is explained in the documentation for the "Initialize()"
procedure (it might have been helpful if the documentation for
GetMem() had mentioned this - or the lack there-of - too - LOL)
So you might find that GetMem() would have worked had you also called
Initialise() on the pointer afterward (and Finalize() before calling
FreeMem()). But whatever the underlying reasons it is obviously
simply much easier and safer (less to remember to have to do, less to
get wrong in doing it :)) to use New/Dispose when working with
allocations of variables/structured(typed) memory and use
GetMem/FreeMem when it is strictly speaking *just* unstructured memory
you need (e.g. i/o buffers etc), rather than space for variables.
Glad it helped with your problem in any event. :)
On 29 August 2011 17:40, David Moorhouse <[email protected]
<mailto:[email protected]>> wrote:
I'm aware of the compiler layout behind the scene - and the fact
that regardless of the length of the dynamic array, my call to
GetMem (or New) does NOT have to allocate memory for the dynamic
array's contents, just it's overhead :)
However, the compiler gets the size right using New rather than
GetMem :) So thanks for the tip.
Cheers
D
On 29/08/11 16:23, Jolyon Smith wrote:
Is it a compiler *error* or just a compiler _behaviour_ ?
I haven't looked into it in detail, but dynamic arrays are
notoriously slippery when you are working with them at a low
level and alarm bells started ringing as soon as I saw they were
involved.
In particular, a dynamic array is a reference type, like a
string. So whilst their may be additional RTTI at a negative
offset from the base address of the array, the "array" itself may
well be a pointer, hence "sizeof()" will return 4 - the size of a
pointer - no matter how many items may be in the array (as
opposed to Length(), obviously).
NOTE: sizeof(String) also yields "4" even though we all know
that a String variable requires many more bytes than that.
As far as this particular example goes, do you get any better
results using the typed New() function rather than GetMem() which
knows nothing about the "type" of memory required by the pointer
you are initialising and just blithely allocates the specified
number of bytes...:
Instead of >> LogData := GetMem( ... );
Use >> New( LogData );
And see if you get better results. :)
(Also, don't forget to use "Dispose()" to deallocate the memory
obtained with "New()", rather than FreeMem())
On 28 August 2011 21:33, David Moorhouse (DUG)
<[email protected] <mailto:[email protected]>> wrote:
I believe it is a compiler error and will raise a QA ticket
Thanks for your help
D
On 26/08/11 08:17, Peter Ingham wrote:
> Try filling LogData with binary zeros after the Getmem&
before the assign.
>
> FillChar (LogData^, sizeof(TLogData), 0);
>
> I believe the uninitialized memory is messing up the
compiler magic
> associated with the dynamic array.
>
>
> Any reason the local Tlogdata record is referenced via a
pointer?
>
> I suspect the following will also work:
> procedure TUserClass.Log(const LogType: TLogType; const
Args: array of
> const );
> var
> LogData: TLogData;
> begin
> LogData.LogType := LogType;
> LogData.LogArgs := CreateConstArray(Args);
> // ... do some other stuff with the LogData item
finally calling
> end;
>
> Cheers
>
> On 26/08/2011 1:49 a.m., David Moorhouse wrote:
>> Hi Peter
>>
>> Been there done that :)
>>
>> The function call is fine. It is the assignment that
causes the AV -
>> because the "bucket" is too small.
>> Assigning it with 16 bytes fixes the problem, regardless
of how many
>> items the array holds.
>>
>> I smell compiler magic in the background.
>>
>> Cheers
>
>> D
>>
>> On 25/08/11 17:29, Peter Ingham wrote:
>>> Another attempt to reply...
>>>
>>> First thing to do is determine if the crash occurs in the
procedure call,
>>> on the subsequent assign, or in between.
>>>
>>> Give this a try:
>>> procedure TUserClass.Log(const LogType: TLogType;
const Args: array of
>>> const );
>>> var
>>> LogData: PLogData;
>>> TempArgs : TConstArray;
>>> begin
>>> // size of record TLogData does not work
>>> GetMem(LogData, sizeof(TLogData));
>>> LogData.LogType := LogType;
>>> // blows up on one of these lines
>>> TempArgs := CreateConstArray(Args);
>>> LogData.LogArgs := TempArgs;
>>> // ... do some other stuff with the LogData item
finally calling
>>> FreeMem
>>> end;
>>>
>>>
>>> Regarding the size of a dynamic array, like a string
variable, the
>>> variable (LogArgs in this case) is the size of a pointer
(i.e. 4 bytes
>>> for Win32). If the pointer is non-zero, it points to a
structure which
>>> includes the adjacent array elements preceded by a length.
>>>
>>> One thing to watch out for is that Getmem does not clear
the allocated
>>> memory, so LogData after the Getmem call will contain any
old rubbish.
>>> The reference to LogData.LogArgs in the assignment may be
>>> dereferencing a non-zero pointer& attempting to use
whatever it
>>> contains.
>>>
>>> Cheers
>>>
>>>
>>> On 25/08/2011 11:40 a.m., David Moorhouse (DUG) wrote:
>>>> I have the following code snippet
>>>>
>>>> <code>
>>>> type
>>>> PConstArray = ^TConstArray;
>>>> TConstArray = array of TVarRec;
>>>>
>>>> function CreateConstArray(const Elements: array of
const): TConstArray;
>>>>
>>>> type
>>>> TLogType = (ltError, ltWarn, ltInfo);
>>>> PLogData = ^TLogData;
>>>> TLogData = record
>>>> LogType: TLogType;
>>>> LogArgs: TConstArray;
>>>> end;
>>>>
>>>> ....
>>>>
>>>> procedure TUserClass.Log(const LogType: TLogType; const
Args: array of
>>>> const );
>>>> var
>>>> LogData: PLogData;
>>>> begin
>>>> // size of record TLogData does not work
>>>> GetMem(LogData, sizeof(TLogData));
>>>> LogData.LogType := LogType;
>>>> // blows up on next line
>>>> LogData.LogArgs := CreateConstArray(Args);
>>>> // ... do some other stuff with the LogData item
finally calling
>>>> FreeMem
>>>> end;
>>>>
>>>> function CreateConstArray(const Elements: array of
const): TConstArray;
>>>> var
>>>> I: Integer;
>>>> begin
>>>> SetLength(Result, Length(Elements));
>>>> for I := Low(Elements) to High(Elements) do
>>>> Result[I] := // assign a TVarRec here
>>>> end;
>>>> </code>
>>>>
>>>> The code that assigns the memory only assigns 8 bytes -
and an access
>>>> violation ensues. If I replace the call to "sizeof"
with the number 16,
>>>> the code works fine.
>>>>
>>>> My understanding of dynamic arrays was that the compiler
created a 4
>>>> byte
>>>> field before the first element that contained the length
of the array.
>>>>
>>>> So why does the sizeof function not reflect this ? And
why do I
>>>> need 16
>>>> bytes not 12 (4 for LogType + 4 for length of array + 4
for array
>>>> pointer)?
>>>> Also regardless of the number of items in the open array
parameter, 16
>>>> bytes works, so it does not relate the length of the
TConstArray.
>>>>
>>>> Your thoughts ?
>>>>
>>>> David
>>>>
>>>>
_______________________________________________
NZ Borland Developers Group - Delphi mailing list
Post: [email protected]
Admin: http://delphi.org.nz/mailman/listinfo/delphi
Unsubscribe: send an email to [email protected] with
Subject: unsubscribe