我有一个函数,将TPicture作为参数并返回TPngImage。为了保留原始图像,我创建了一个TPngImage并将TPicture复制到TPngImage,应用效果并返回TPngImage。就这样
function Effect( const Value : TPicture ) : TPngImage;
var
AnImage : TPngImage;
begin
if( Value.Graphic is TPngImage ) then
begin
AnImage := TPngImage.Create();
AnImage.Assign( TPngImage( Value ) );
//Apply effect
Result := AnImage;
//AnImage.Free(); //error
end;
end;
procedure TForm11.Button1Click( Sender : TObject );
begin
Image2.Picture.Assign( Effect( Image1.Picture ) );
end;
在创建对象时,何时释放创建的对象。我不能在函数中调用TPngImage.Free(),因为它会在分配之前破坏对象。那么如何释放创建的对象?当对象超出范围时,TPngImage是否调用其析构函数?据我所知,不释放对象将导致内存泄漏。
最佳答案
您的代码中包含几个错误:
if( Value.Graphic is TPngImage ) then
如果呼叫者的
TPicture
尚未包含TPNGImage
,则根本不返回任何内容。 Result
未定义。实际上,您根本不需要检查
Graphic
的类型。可以将各种TGraphic
类分配给彼此,将其图像数据从一种格式转换为另一种格式,因此应尽可能进行这种转换。AnImage.Assign( TPngImage( Value ) );
您正在强制转换
TPicture
本身。您需要改型其Graphic
。Result := AnImage;
//AnImage.Free();
这要求调用者获得
TPNGImage
的所有权并释放它,这通常是一个不好的设计。Image2.Picture.Assign( Effect( Image1.Picture ) );
举例来说,调用者没有获得返回的
TPngImage
的所有权,因此它被泄漏了。如果要返回新的
TPNGImage
,请尝试以下方法:function Effect(Value : TPicture) : TPngImage;
begin
Result := TPngImage.Create;
try
if (Value.Graphic <> nil) and (not Value.Graphic.Empty) then
begin
Result.Assign(Value.Graphic);
//Apply effect
end;
except
Result.Free;
raise;
end;
end;
要么
function Effect(Value : TPicture) : TPngImage;
begin
Result := nil;
if (Value.Graphic <> nil) and (not Value.Graphic.Empty) then
begin
Result := TPngImage.Create;
try
Result.Assign(Value.Graphic);
//Apply effect
except
Result.Free;
raise;
end;
end;
end;
无论哪种方式,您都可以这样做:
procedure TForm11.Button1Click(Sender : TObject);
var
AImage: TPngImage;
begin
AImage := Effect(Image1.Picture);
try
Image2.Picture.Assign(AImage);
finally
AImage.Free;
end;
end;
但是,更好的设计是根本不返回新的
TPngImage
。传入2个TPicture
对象,然后让Effect()
根据需要对其进行操作:procedure Effect(Input, Output : TPicture);
var
AnImage : TPngImage;
begin
AnImage := TPngImage.Create;
try
if (Input.Graphic <> nil) and (not Input.Graphic.Empty) then
begin
AnImage.Assign(Input.Graphic);
//Apply effect
end;
Output.Assign(AnImage);
finally
AnImage.Free;
end;
end;
要么
procedure Effect(Input, Output : TPicture);
var
AnImage : TPngImage;
begin
if (Input.Graphic <> nil) and (not Input.Graphic.Empty) then
begin
AnImage := TPngImage.Create.Create;
try
AnImage.Assign(Input.Graphic);
//Apply effect
Output.Assign(AnImage);
finally
AnImage.Free;
end;
end else
Output.Assign(nil);
end;
然后,您可以执行以下操作:
procedure TForm11.Button1Click(Sender : TObject);
begin
Effect(Image1.Picture, Image2.Picture);
end;