Consider the following two programs, Program 1 first:
program Project1;
{$mode objfpc}{$H+}
type
PSomeRec = ^TSomeRec;
TSomeRec = record
a: string;
b: string;
end;
// COPY OF POINTER IS ALLOCATED, PASSING BY VALUE
procedure ChangeRec1(Rec: PSomeRec);
begin
new(Rec); // WRONG
Rec^.a:= 'string A';
end;
var
RecPtr: PSomeRec;
begin
ChangeRec1(RecPtr);
writeln(RecPtr^.a);
dispose(RecPtr);
readln;
end.
versus program 2 below:
program Project2;
{$mode objfpc}{$H+}
type
PSomeRec = ^TSomeRec;
TSomeRec = record
a: string;
b: string;
end;
// COPY IS NOT ALLOCATED, PASSING BY REFERENCE
procedure ChangeRec1(var Rec: PSomeRec);
begin
new(Rec); // OKAY TO DO
Rec^.a:= 'string A';
end;
var
RecPtr: PSomeRec;
begin
ChangeRec1(RecPtr);
writeln(RecPtr^.a);
dispose(RecPtr); // okay because we are freeing the same reference
readln;
end.
Now consider program 3 which still works but is not recommended:
program Project3;
{$mode objfpc}{$H+}
type
PSomeRec = ^TSomeRec;
TSomeRec = record
a: string;
b: string;
end;
// COPY IS NOT ALLOCATED, PASSING BY REFERENCE
procedure ChangeRec1(const Rec: PSomeRec);
begin
Rec^.a:= 'string A'; // you can access pointed to data, even if Rec is read-only
end;
var
RecPtr: PSomeRec;
begin
new(Rec);
ChangeRec1(RecPtr);
writeln(RecPtr^.a);
dispose(RecPtr);
readln;
end.
Even though the Rec parameter is read-only, one can still access the fields inside the pointed to data. You may not however do this:
procedure ChangeRec1(const Rec: PSomeRec);
begin
new(Rec);
Rec:= something; // can't do it, Rec *itself* is read only
end;
Nor can you do this and expect to pass the parameter out of the function:
procedure ChangeRec1(Rec: PSomeRec);
begin
new(Rec); // allocating a local copy inside function! passed by value.
Rec^.a:= 'string A';
Rec:= Rec;
end; // Rec no longer available when function ends!
You must do it this way:
procedure ChangeRec1(var Rec: PSomeRec);
begin
new(Rec); // allocating a local new copy, passed by value
Rec^.a:= 'string A';
Rec:= Rec;
end; // Rec is not a copy, and is available when function ends
|