Jump to content
RaelB

Invalid pointer operation when try to replace object in list

Recommended Posts

I create a number of Frames and store them in a Frame Object List (declared as FFrames: TObjectList<TMyFrame>)

The frames are also added to the VCL form.

 

I try to replace a Frame with below code, but it results in an "Invalid Pointer Operation": (I'm replacing the last Frame in the list with a new one)

 

procedure TForm1.btnReplaceClick(Sender: TObject);
var
  NewFrame: TMyFrame;
  OldFrame: TMyFrame;
begin
  if FFrames.Count = 0 then exit;

  NewFrame := GetNewFrame;
  OldFrame := FFrames[FFrames.Count - 1];
  FFrames[FFrames.Count - 1] := NewFrame;
  OldFrame.Free;
end;

What's wrong with the code?

 

Full code follows:

 

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls,
  System.Generics.Collections, MyFrameU;

type
  TForm1 = class(TForm)
    ScrollBox1: TScrollBox;
    btnAdd: TButton;
    btnReplace: TButton;
    procedure btnAddClick(Sender: TObject);
    procedure btnReplaceClick(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
    FFrames: TObjectList<TMyFrame>;
    function GetNewFrame: TMyFrame;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  Counter: Integer;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
  FFrames := TObjectList<TMyFrame>.Create;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  FFrames.Free;
end;

function TForm1.GetNewFrame: TMyFrame;
begin
  Result := TMyFrame.Create(Self);
  Result.Name := 'MyFrame' + Counter.ToString;
  Result.Parent := ScrollBox1;
  Result.Align  := alLeft;
  Result.SetName(Result.Name);
  Inc(Counter);
end;

procedure TForm1.btnAddClick(Sender: TObject);
var
  Frame: TMyFrame;
begin
  Frame := GetNewFrame;
  FFrames.Add(Frame);
end;

procedure TForm1.btnReplaceClick(Sender: TObject);
var
  NewFrame: TMyFrame;
  OldFrame: TMyFrame;
begin
  if FFrames.Count = 0 then exit;

  NewFrame := GetNewFrame;
  OldFrame := FFrames[FFrames.Count - 1];
  FFrames[FFrames.Count - 1] := NewFrame;
  OldFrame.Free;
end;

end.

 

Share this post


Link to post

Thanks - didn't realise it would affect the operation I was doing.

Edited by RaelB

Share this post


Link to post

So, if I keep OwnObjects True, I can just call:

  FFrames[FFrames.Count - 1] := GetNewFrame;

I don't need to worry about Freeing the previous object.

  • Like 1

Share this post


Link to post

by doing it this way, you're saying something like this: ob1 now you're obj2... so wouldn't it be more correct for you to "remove obj1" and "add obj2"?  

see procedure "Remove()" and "Add()" from the list.

 if the list is not the "owner" of the object then you will need to release it from memory to avoid memory leak

Share this post


Link to post
Quote

you're saying something like this: ob1 now you're obj2...

Well no. We're not saying ob1 is now obj2. The ObjectList is pointing to one object, then pointing to a different object. And when you make that change, it automatically frees the first object. This I didn't know before.. 🙂

Share this post


Link to post
13 hours ago, programmerdelphi2k said:

wouldn't it be more correct for you to "remove obj1" and "add obj2"?  

see procedure "Remove()" and "Add()" from the list

No. 

 

13 hours ago, programmerdelphi2k said:

if the list is not the "owner" of the object then you will need to release it from memory to avoid memory leak

When OwnsObjects is true, as it is here, the list is the owner. 

Share this post


Link to post
18 hours ago, RaelB said:

So, if I keep OwnObjects True, I can just call:


  FFrames[FFrames.Count - 1] := GetNewFrame;

I don't need to worry about Freeing the previous object.

Yes. 

Share this post


Link to post
On 2/11/2023 at 3:10 PM, Alexander Sviridenkov said:

By default TObjectList owns contained objects. So create it with False parameter in constructor or use Extract to remove object from list.

Or, use TList<TMyFrame> instead, which doesn't try to own objects.

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×