參考APG裡的說法:平台差異及不兼容性的一個特別的方面,是對象的運行時初始化和程序關閉時這些對象的相應析構。
ACE為了明確管理對象的清理,定義了ACE_Object_Manager類,這個類不僅涉及到對象的管理,還與ACE庫的初始化與關閉相關。
ACE中應用了大量的設計模式,本篇順便研究ACE的程序入口函數替換機制分析。
ACE庫的初始化與關閉
應用要確保在使用ACE庫時正確的初始化和關閉,有以下兩種常用方式:
1、使用ACE_TMAIN宏作為程序入口函數;
2、使用ACE::init()和ACE::fini()明確初始化和關閉ACE庫。
ACE_TMAIN宏會對程序入口函數進行替換,已在程序執行前和執行後加入初始化代碼,對ACE程序入口函數替換機制分析,可以使用編譯器展開ACE_TMAIN的代碼:
int ace_main_i (int, char *[]); __declspec (dllimport) int ace_os_main_i (ACE_Main_Base&, int, char *[]); class ACE_Main : public ACE_Main_Base { int run_i (int, char *[]);}; inline int ACE_Main::run_i (int argc, char *argv[]) { return ace_main_i (argc, argv); } int main (int argc, char *argv[]) { ACE_Main m; return m.run (argc, argv); } int ace_main_i (int argc, ACE_TCHAR * argv[]) { return 0; }
可以看到真正的main函數體被替換為:ACE_Main m; return m.run (argc, argv);而程序代碼被包括到ace_main_i函數中。
ACE_Main的實例對象m是一個main函數內的棧對象,在main函數開始構造,在函數的結束析構。
ACE_Main類是一個生成類,繼承自ACE_Main_Base類,調用其run函數。
ACE_Main_Base在ace/Os_main.h類中定義,代碼片段如下:
ACE_Main_Base::ACE_Main_Base () { ACE::init (); } ACE_Main_Base::~ACE_Main_Base () { ACE::fini (); } int ACE_Main_Base::run (int argc, char *argv[]) { return this->run_i (argc, argv); }
可以看到其構造函數和析構函數也分別通過ACE::init()和ACE::fini()初始化和關閉ACE庫。
研究ACE的宏展開也學習一種入口函數替換機制。
跟蹤ACE::init()
通過展開ACE_TMAIN宏,發現最終還是在main函數的開始初調用了ACE::init函數,這個函數定義在ace/Init_Ace.cpp中:
int ACE::init (void) { // Don't use ACE_TRACE, because Object_Manager might not have been // instantiated yet. // ACE_TRACE ("ACE::init"); ++ACE::init_fini_count_; return ACE_Object_Manager::instance ()->init (); }
init的函數體非常簡單,就是初始化ACE_Object_Manager,也就回到本文開始的主體:這個類不僅涉及到對象的管理,還與ACE庫的初始化與關閉相關。
fini函數與此類似,調用了ACE_Object_Manager的清理函數,有興趣的可以查看源代碼。
ACE_Object_Manager
ACE_Object_Manager類之所以與ACE庫的初始化和關閉相關,是因為ACE_Object_Manager不僅可以幫助應用能按正確的方式清理對象,ACE庫內部的對象管理也依賴於ACE_Object_Manager。
至於ACE_Object_Manager的init函數中的代碼可以不必過多深究,主要是實例化一組ACE對象,用以給ACE的內部機制提供支持,並在關閉時銷毀這些對象。
ACE_Object_Manager提供了at_exit函數,允許應用向其登記對象,並在關閉時會以登記次序相反的次序銷毀所登記的對象。
向ACE_Object_Manager登記的對象必須繼承自ACE_Cleanup,並實現cleanup()方法進行清理工作;對於基本類型的對象可以使用at_exit的重載函數傳遞一個ACE_CLEANUP_FUNC的回調函數。
ACE_Object_Manager的API:http://www.dre.vanderbilt.edu/Doxygen/6.0.0/html/libace-doc/a00355.html
要保證ACE_Object_Manager能夠正確的清理對象,必須滿足以下兩條:
1、永遠不要直接調用exit(),讓main函數通過return返回(推薦閱讀:exit & abort & 析構 & 異常 );
2、確保ACE_Object_Manager成功初始化。
ACE非常有名的單例模式也是關聯到ACE_Object_Manager,後期有機會單獨寫出來。
記錄,為更好的自己!