全國最多中醫師線上諮詢網站-台灣中醫網
發文 回覆 瀏覽次數:1769
推到 Plurk!
推到 Facebook!

Delphi 免寫 FreeAndNil 的方法

 
GrandRURU
站務副站長


發表:234
回覆:1648
積分:1741
註冊:2005-06-21

發送簡訊給我
#1 引用回覆 回覆 發表時間:2016-08-26 08:25:43 IP:59.120.xxx.xxx 未訂閱
或許你會羨幕那些已經內建垃圾回收機制的語言,如 C#、Java 等。

如果 Delphi 有那麼一天提供了,你會使用嗎?

Delphi 免寫 FreeAndNil 的方法
leveon
資深會員


發表:29
回覆:386
積分:303
註冊:2012-02-12

發送簡訊給我
#2 引用回覆 回覆 發表時間:2016-08-26 14:21:17 IP:1.161.xxx.xxx 訂閱
坦率地講 依你舉的例子  用Object更簡潔 無需create 自然無回收問題

TMyImplClass = Object
aa:string;
BB:string;
procedure P1;
procedure P2;
end;

{ TMyImplClass }

procedure TMyImplClass.P1;
begin
showmessage(aa);
end;

procedure TMyImplClass.P2;
begin
showmessage(bb);
end;

//---------------- call
var
MyImplClass:TMyImplClass;
begin
MyImplClass.aa := '1111';
MyImplClass.bb := '2222';
MyImplClass.P1;
MyImplClass.P2;






===================引 用 GrandRURU 文 章===================
或許你會羨幕那些已經內建垃圾回收機制的語言,如 C#、Java 等。

如果 Delphi 有那麼一天提供了,你會使用嗎?

Delphi 免寫 FreeAndNil 的方法
GrandRURU
站務副站長


發表:234
回覆:1648
積分:1741
註冊:2005-06-21

發送簡訊給我
#3 引用回覆 回覆 發表時間:2016-08-26 15:11:53 IP:59.120.xxx.xxx 未訂閱
謝謝 leveon 大的分享!
===================引 用 leveon 文 章===================
坦率地講 依你舉的例子 用Object更簡潔 無需create 自然無回收問題

TMyImplClass = Object
aa:string;
BB:string;
procedure P1;
procedure P2;
end;

{ TMyImplClass }

procedure TMyImplClass.P1;
begin
showmessage(aa);
end;

procedure TMyImplClass.P2;
begin
showmessage(bb);
end;

//---------------- call
var
MyImplClass:TMyImplClass;
begin
MyImplClass.aa := '1111';
MyImplClass.bb := '2222';
MyImplClass.P1;
MyImplClass.P2;






===================引 用 GrandRURU 文 章===================
或許你會羨幕那些已經內建垃圾回收機制的語言,如 C#、Java 等。

如果 Delphi 有那麼一天提供了,你會使用嗎?

Delphi 免寫 FreeAndNil 的方法
pcplayer99
尊榮會員


發表:141
回覆:733
積分:589
註冊:2003-01-21

發送簡訊給我
#4 引用回覆 回覆 發表時間:2016-08-28 23:43:56 IP:183.17.xxx.xxx 訂閱
我觉得你的文章,把 Interface 搞复杂了。

以下是我的 code:

IMyIntf = interface
['{8181ABA3-E0B8-4B8D-B49B-93C7723CB280}']
function Hello(const S: string): string;
end;

TMyObj = class(TInterfacedObject, ImyIntf)
public
destructor Destroy; override;
function Hello(const S: string): string;
end;
--------------

procedure TForm1.Button1Click(Sender: TObject);
var
Obj: TMyObj;
Intf: IMyIntf;
begin
Obj := TMyObj.Create;
Intf := Obj as IMyIntf;
Label1.Caption := Intf.Hello('abc');
end;

{ TMyObj }
destructor TMyObj.Destroy;
begin
ShowMessage('Destroy...ed');
inherited;
end;

结论:只要是从 TInterfacedObject 继承下来的 Class,它的 Object 你用了 Interface,只要 Interface 的引用被释放,它就会自动的被释放。 你的 Blog 中的例子是,这个 Object 里面,还有一个内建的 Object。出问题的是那个内建的 Object。 这里,正确的写法,应该是在这个 Object 的 constructor 里面,写内建 Object 的 Create 方法;在 destructor 里面,写内建的 Object 的 Free 方法。 总之,只要是记得,在哪里创建的,就在哪里释放,基本上就不会有忘记释放带来的内存泄漏(Memory leak)。 有一种情况是,你创建了一个 Object,要把它丢进一个 pool 比如一个 List 等待其它 unit 的其它 Thread 去处理。这种情况下,就很难让代码从架构上做到哪里创建的在哪里释放。这种情况下,最简单的方式就是采用从 TInterfacedObject 继承,然后用它的 interface 的方式,就可以完美解决。 更进一步,如果上述的 Object 需要频繁的创建和释放,采用 TInterfacedObject 继承来就有问题。频繁的创建和释放会带来运行效率的开销。 这时候,需要有一个 Pool 机制来处理这个问题。 最简单的 Pool 机制,就是用类工厂模式,你需要的多个interface实例,让类工厂创建。类工厂内部有一个 List,创建好的都丢进这个 List。在代码中用完释放的 interface 因为在类工厂的 List 里面还有一个引用,它就不会被释放。需要的时候还可以拿出来再次使用。 说来说去,一个 Object,它不只是方法的集合,同时还包括 Data。一个 Class 可以看做是 Method 的集合。从一个 Class 创建的多个不同的 Object,它的 Data 或者 Property 可能不相同。 如果仅仅要方法,直接用 Class 的 Class function 就好了。用 Class function 不需要去创建它的 Object 实例。
編輯記錄
pcplayer99 重新編輯於 2016-08-28 23:48:22, 註解 無‧
GrandRURU
站務副站長


發表:234
回覆:1648
積分:1741
註冊:2005-06-21

發送簡訊給我
#5 引用回覆 回覆 發表時間:2016-08-29 09:11:03 IP:59.120.xxx.xxx 未訂閱
Class function 在物件實作上是很有威力的。

寫了很久的程式,也很少用到它,真是有趣。

謝謝您無私的分享!

===================引 用 pcplayer99 文 章===================
我觉得你的文章,把 Interface 搞复杂了。

以下是我的 code:

IMyIntf = interface
['{8181ABA3-E0B8-4B8D-B49B-93C7723CB280}']
function Hello(const S: string): string;
end;

TMyObj = class(TInterfacedObject, ImyIntf)
public
destructor Destroy; override;
function Hello(const S: string): string;
end;
--------------

procedure TForm1.Button1Click(Sender: TObject);
var
Obj: TMyObj;
Intf: IMyIntf;
begin
Obj := TMyObj.Create;
Intf := Obj as IMyIntf;
Label1.Caption := Intf.Hello('abc');
end;

{ TMyObj }
destructor TMyObj.Destroy;
begin
ShowMessage('Destroy...ed');
inherited;
end;

结论:只要是从 TInterfacedObject 继承下来的 Class,它的 Object 你用了 Interface,只要 Interface 的引用被释放,它就会自动的被释放。 你的 Blog 中的例子是,这个 Object 里面,还有一个内建的 Object。出问题的是那个内建的 Object。 这里,正确的写法,应该是在这个 Object 的 constructor 里面,写内建 Object 的 Create 方法;在 destructor 里面,写内建的 Object 的 Free 方法。 总之,只要是记得,在哪里创建的,就在哪里释放,基本上就不会有忘记释放带来的内存泄漏(Memory leak)。 有一种情况是,你创建了一个 Object,要把它丢进一个 pool 比如一个 List 等待其它 unit 的其它 Thread 去处理。这种情况下,就很难让代码从架构上做到哪里创建的在哪里释放。这种情况下,最简单的方式就是采用从 TInterfacedObject 继承,然后用它的 interface 的方式,就可以完美解决。 更进一步,如果上述的 Object 需要频繁的创建和释放,采用 TInterfacedObject 继承来就有问题。频繁的创建和释放会带来运行效率的开销。 这时候,需要有一个 Pool 机制来处理这个问题。 最简单的 Pool 机制,就是用类工厂模式,你需要的多个interface实例,让类工厂创建。类工厂内部有一个 List,创建好的都丢进这个 List。在代码中用完释放的 interface 因为在类工厂的 List 里面还有一个引用,它就不会被释放。需要的时候还可以拿出来再次使用。 说来说去,一个 Object,它不只是方法的集合,同时还包括 Data。一个 Class 可以看做是 Method 的集合。从一个 Class 创建的多个不同的 Object,它的 Data 或者 Property 可能不相同。 如果仅仅要方法,直接用 Class 的 Class function 就好了。用 Class function 不需要去创建它的 Object 实例。
rocklee
一般會員


發表:0
回覆:2
積分:0
註冊:2004-07-25

發送簡訊給我
#6 引用回覆 回覆 發表時間:2017-05-16 08:35:51 IP:183.238.xxx.xxx 未訂閱
正解.
===================引 用 leveon 文 章===================
坦率地講 依你舉的例子 用Object更簡潔 無需create 自然無回收問題

TMyImplClass = Object
aa:string;
BB:string;
procedure P1;
procedure P2;
end;

{ TMyImplClass }

procedure TMyImplClass.P1;
begin
showmessage(aa);
end;

procedure TMyImplClass.P2;
begin
showmessage(bb);
end;

//---------------- call
var
MyImplClass:TMyImplClass;
begin
MyImplClass.aa := '1111';
MyImplClass.bb := '2222';
MyImplClass.P1;
MyImplClass.P2;






===================引 用 GrandRURU 文 章===================
或許你會羨幕那些已經內建垃圾回收機制的語言,如 C#、Java 等。

如果 Delphi 有那麼一天提供了,你會使用嗎?

Delphi 免寫 FreeAndNil 的方法
系統時間:2017-09-25 1:33:29
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!