2016/10/31

淺談物件的釋放以及使用時機的探討 -- 使用 RAD Studio C++ Builder Berlin


據說,未來是個沒有 Delete 的世界(大誤) 圖片來源

在說明物件釋放方法之前,還得先聊聊 C++ Builder 開發者的習慣

就目前所接觸到會使用 C++ Builder 的開發者所整理的經驗,他們使用 C++ Builder 的理由大致上是以下兩點:
  1. 本身具有極高的 C 語言造詣,通常具有硬體開發經驗
  2. 和 Visual Studio C++ 相比,C++ Builder 的 UI 更是直覺的建立

由 1 可知,會使用 C 語言的開發者,通常有很強烈的語言潔癖,以及有自己一套對記憶體控制的要求

由 2 可知,C++ Builder 對從 C 過來的開發者來說,是很棒的 UI 建模工具

<以下 C++ Builder 簡稱 CB>
 
只是,由於 CB 的 WinForm 是建構在 VCL framework 之上,所以學習 C++ 的物件自然是必須要的。在擴充C++的基本知識後,底下便是常見的寫法:


TForm2* tmpForm = new TForm2(NULL);
tmpForm.DoSomething...
delete tmpForm;

這是很標準的 C++ 寫法,乾乾淨淨,一切都操之在我

只是當一個函式裡物件一多,就會有以下的程式碼狀況:

T...new ...
T...new ...
T...new ...
T...new ...
T...new ...
DoSomething...
delete T...
delete T...
delete T...
delete T...

看一下上面的程式碼有什麼問題?



















少了一列 delete T...!
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
還是別耍冷了,進入正題……

所以證明以上的程式並不完全是個好寫法,但這篇並不探討更好的設計模式,只是如果想稍微偷懶一下,可以這樣寫:
void Method...
{
TForm2* tmpForm = new TForm2(this);
DoSomething...
}

就這樣,沒了,看起來十分簡單吧

上文最關鍵的地方就是:
new TForm2(this);

這一列來自於 VCL framework,所有 VCL framework 的可視元件,都是繼承自 TComponent 來的,所以只需要給繼承自 TComponent 的物件就能做到跟隨該物件釋放,這個範例是this,也就是 this 物件被 delete 時,tmpForm 也會跟著被 delete


接下來便是非繼承自 TComponent 物件的場合,要如何偷懶呢?


要知道,C++是非常先進的語言之一,像 JAVA、C#那樣的自動回收機制想當然是小菜一碟

在 C++ 標準函式庫裡有個叫做【auto_ptr】的智慧指標,它就是專門用來實現 C++ 的自動回收釋放


那麼……要怎樣才能實作出來呢?


實作上只要先宣告:
#include  
using namespace std;

之後就可以這樣寫:

//TForm2* tmpForm = new TForm2(NULL);
auto_ptr<Tform2>tmpForm(new TForm2(NULL));
tmpForm->DoSomething...
//delete tmpForm;

程式碼看起來又更簡潔了呢!


身為一個有彈性,又十分先進的語言,優雅當然也是必須要的


而且,新版 RAD Studio 已經支援行動平台,要知道行動平台是利用什麼語言開發的:
  • Android ► JAVA
  • iOS ► Objective-C

兩個共通特點就是:它們語言特性都具備【物件自動回收】機制

Delphi 實現的方式為:ARC (Automatic Reference Counting)

到 Delphi 最近才把這個功能做完整之前(從沒有支援到可以使用 DisposeOf 到不再需要Free的完整支援間,花了將近 5 個年頭)


CB 早已透過 C++強大的標準函式庫功能,率先支援 ARC。


CB 使用者真的很幸福啊!

附帶一提,CB 在 Berlin 版本之後已經完整支援 C++11 標準,按照 C++11 規格書已經 auto_ptr 列為【棄用】(deprecated)的情況來看

它們主要差別在智慧指標互相傳遞的差異

auto_ptr<T>P1(new T());
auto_ptr<T>P2(new T());
P1 = P2 ; ◀ 這是可以的

unique_ptr<T>P1(new T());
unique_ptr<T>P2(new T());
P1 = P2 ; ◀ 編譯時就會跳 Error

所以建議使用新版CB時應採用【unique_ptr】方式實作(實作方式同 auto_ptr)才好,這是在官方文件上還沒有更新的部份,僅供您做個參考……的動作

unique_ptr 改良 auto_ptr 對初始指標的釋放管理

結論:
循規蹈距手工管理很好,能夠靈活應用平台特性更棒,您說是吧!



See also:


沒有留言:

張貼留言