Record structs with strings have always confused me a little in Delphi. Can
anyone explain why if you use GetMem for a record struct and try to access a
string value you will get an AV while the same code with AllocMem will work
fine.
For Example:
Type TMyRec = record
s1 : String;
SomeInt : integer;
end;
........
procedure produce;
var p : pointer;
begin
GetMem( p, SizeOf( TMyRec ) );
TMyRec(p^).s1 := 'hello'; //<--------AV here
end;
procedure OK;
var p : pointer;
begin
p := AllocMem( SizeOf( TMyRec ) );
TMyRec(p^).s1 := 'hello';
end;
End Example----
Thanks in advance,
David Saracini
>why if you use GetMem for a record struct and try to access a
>string value you will get an AV while the same code with AllocMem will work
>fine.
AllocMem zero-initializes the memory, GetMem does not.
With GetMem, you simply access a garbage string. With AllocMem, you
initialize an emptry (nil) string.
--
Stefan Hoffmeister (TeamB) http://www.econos.de/
Please do apply judgement when sending email.
Stefen's correct, of course. But OP is built to avoid this, if you just use
it's type facilities --
procedure produce;
var p : ^TmyRec;
begin
new(p);
p.s1 := 'hello'; // no AV
end;
When you define p by the actual type it point to, New calls Initialize,
which carefully goes over the thing pointed to an nulls all strings (even in
sub-sub-structures), among other things.
PhR
Why does it AV when you try to set it? Please see the Produce method is the
original posting.
David
Thanks for the tip... That works great... I had used a "Typed" Pointer
with the GetMem call, but it didn't make a difference. Borland should do a
little better job documenting GetMem and recommending that developers use
New.
However, is there anything wrong with the way that I'm using AllocMem in my
original posting (except for the fact that in that simple example I'm not
call FreeMem)? In other words, do I need to go back and find all of the
places where I'm using AllocMem and change my code to use New instead?
Thanks for your help.
Best Regards,
David Saracini
Philippe Ranger <.> wrote in message <7mlf18$66...@forums.borland.com>...
Because you are using for a string address (string var contents) a random
collection of 32 bits. Chances are it points somewhere your program does not
have access to -- Access Violation.
PhR
Definitely!
PhR
>>Please see the Produce method is the
>>original posting.
I saw that.
>Why does it AV when you try to set it?
Because AnsiString is reference-counted and with every string write you
automatically get a (required) string read, too - in particular to test
whether the reference-count is > 1.
That requires access to the pointer. Since the pointer is garbage - boom.
>In other words, do I need to go back and find all of the
>places where I'm using AllocMem and change my code to use New instead?
It is better style and safer, yes.
Besides, if you called FreeMem on the allocated memory, you'd get some
nice memory leaks due to the highly likely fact that you'd have forgotten
to call Finalize.
Thank you both for the good advice!
David
I always use New for creating new memory for record types, but for some
reason I always use GetMem when I want some memory for a PChar.
Should I always use New ?
/Mikael
Philippe Ranger <.> wrote in message <7mmajs$6l...@forums.borland.com>...
> Hi Phil,
> I've acually been wondering for a while now... What is really the difference
> between GetMem and New ?
New=GetMem+Initialize
AllocMem=GetMem+FillChar
GetMem= actually gets memory
Dispose = Finalize + FreeMem
FreeMem = frees memory
> Should I always use New ?
No, You can't set the size with New. You should probably use AllocMem. This
will pre-zero your data ensuring that you have a valid string from the start.
--
Bob Lee
High Performance Delphi - http://www.econos.com/optimize/
When the compiler can't determine the amount of memory needed,
you need GetMem.
New is one of these magic functions. It knows about the type and the
size of the object that you create. New calls GetMem to get the raw
memory and then calls Initialize to properly Initialize it. Always use
New/Dispose for records you allocate.
Bill
Should I always use New ?
>>
Here's the entire code for _New --
------------
procedure _New{ size: Longint; typeInfo: Pointer};
asm
{ -> EAX size of object to allocate }
{ EDX pointer to typeInfo }
PUSH EDX
CALL _GetMem
POP EDX
TEST EAX,EAX
JE @@exit
PUSH EAX
CALL _Initialize
POP EAX
@@exit:
end;
------------
As you can see, the compiler replaces your call to New with one to _New, and
quite a bit of info about **the pointer type you're newing**. As long as you
use honest pointer types (no casting, etc.), the whole Delphi system works
on your side when you use New.
What actually happens is this. GetMem (ok, _GetMem) gets called on the
declared size for what the pointer points to. Then, if there's anything
special about that thing (i.e. myPointerType^), _Initialize gets called.
Initialize ensures that strings, dynArrays, variant arrays and interfaces
initialize to nil, which is absolutely essential for those things to work
correctly. The bug from not using initialize may or may not show up in
tests, because in tests you have lots of memory which happens to be zero.
Not in real life.
When Borland adds more stuff to OP, Initialize will again be added to so
that the new stuff works to.
So, the Simple-Simon reason for using New is that OP is a typed language,
and GetMem is untyped. The Savvy-Sally reason is that New correctly calls
Initialize.
*Exactly* the same reasons say you should use Dispose, not FreeMem.
About the pChar thing -- You almost never have to getMem on a pChar. In many
cases, you already have a string around with the correct contents, and all
you have to do is use pChar(myString). In other cases, either you don't, or
the pChar^ will be changed. Then you use a string again --
setLength(myString, sizeNeeded);
doMyThing(pChar(myString));
myString := pChar(myString); //to reset the length
Advantage is that you can then use string functions, and you have no worry
about deallocation.
PhR