Consider these two standalone functions

Consider these two standalone functions

function CaptureList: TArray;

procedure LogList(const aList: TArray);

and the two following use cases:

This one works,

procedure TSomeClass.Case1;

var

List: TArray;

begin

List := CaptureList;

LogList(CaptureList);

end;

but this one fails.

procedure TSomeClass.Case2;

begin

LogList(CaptureList);

end; <- EInvalidPointer in _DynArrayClear on exit

Does anyone see any potential reason why the second fails?

Berlin 10.1 Update 2 Enterprise

12 thoughts on “Consider these two standalone functions


  1. I have no 10.1 here, but will it work if you declare the method this way?


    procedure LogList(aList: TArray); // removed the const


  2. As always – it is complicated. Multiple threads, multiple units, and the values of each element of the list is copied line by line into elements of a separate type (record with a string field) at the innermost point. The record will exist for a longer period of time after the calls are completed.


    I just find it odd that it works with a local list, but not without it.


  3. Works fine for me. Does this work for you? If it does, then it’s something else and you’ve provided not enough information.


    type


    TForm1 = class(TForm)


    Button1: TButton;


    procedure Button1Click(Sender: TObject);


    private


    { Private declarations }


    protected


    { Protected declarations }


    public


    { Public declarations }


    procedure Case1;


    procedure Case2;


    end;


    implementation


    {$R *.dfm}


    function CaptureList: TArray;


    begin


    Result := TArray.Create(‘One’, ‘Two’, ‘Three’);


    end;


    procedure LogList(const aList: TArray);


    begin


    Showmessage(aList[1]);


    end;


    procedure TForm1.Case1;


    var


    List: TArray;


    begin


    List := CaptureList;


    LogList(CaptureList);


    end;


    procedure TForm1.Case2;


    begin


    LogList(CaptureList);


    end;


    procedure TForm1.Button1Click(Sender: TObject);


    begin


    Case1;


    Case2;


    end;


  4. Lars Fosdal If it happens in multithreaded environment then I guess is is because the const is causing the refcount to not be increased for the duration of that routine to run which means that while some other code runs it might reach zero too early and the array gets finalized which causes the invalid pointer exception.


  5. Lars Fosdal Because no other threads are using the same local variable? The second code block you posted in OP suggests it’s shared if not local.


  6. procedure LogList(aList: TArray);


    would indeed solve the problem. It would not lead to any duplication. This is a dynamic array rather than an open array. What would be copied by value is the reference to the array. And that copy requires reference counting which is what keeps your array alive.


    I don’t much care for it though. I’d much rather that the compiler would hold a reference for duration of the function call, from the outside. That would allow the use of const and not force all consumers of the function to increment reference counts needlessly.

Leave a Reply