在我自己寫(xiě)的一個(gè)工廠類(lèi)實(shí)現(xiàn)中,每個(gè)產(chǎn)品會(huì)注冊(cè)創(chuàng)建接口到這個(gè)工廠類(lèi)。工廠類(lèi)使用這些
注冊(cè)進(jìn)來(lái)的創(chuàng)建接口來(lái)完成產(chǎn)品的創(chuàng)建。其結(jié)構(gòu)大致如下:
product *factory::create( long product_type )
{
creator c = m_creators[product_type];
return c();
}
factory::instance().register( PRODUCT_A_TYPE, productA::create );
...
factory::instance().create( PRODUCT_A_TYPE );
這個(gè)很普通的工廠實(shí)現(xiàn)中,需要寫(xiě)上很多注冊(cè)代碼。每次添加新的產(chǎn)品種類(lèi)時(shí),也需要修改
這些的注冊(cè)代碼。而恰好,這些注冊(cè)代碼可能會(huì)被放在一個(gè)統(tǒng)一的地方。為了消除這個(gè)地方
,我使用了偶然間看到的<Modern C++ design>里的做法:
const bool _local = factory::instance().register( PRODUCT_A_TYPE,...
也就是說(shuō),通過(guò)對(duì)全局常量_local的自動(dòng)初始化,來(lái)自動(dòng)完成對(duì)該產(chǎn)品的注冊(cè)。
結(jié)果,因?yàn)檫@些代碼全部被放置于一個(gè)靜態(tài)庫(kù)。最終的代碼文件結(jié)構(gòu)大致為:
lib
- product_a.cpp : 定義了全局常量_local
- product_a.h
- factory.cpp
- factory.h
exe
- main.cpp
現(xiàn)在看起來(lái)世界很美,因?yàn)閒actory甚至不知道世界上還有個(gè)跟上層邏輯相關(guān)的product_a。
這種模塊耦合幾乎為0的結(jié)構(gòu)讓我竊喜。
悲劇的事情首先發(fā)生于,開(kāi)VC調(diào)試器,發(fā)現(xiàn)打在product_a.cpp里的斷點(diǎn)失效。就是那個(gè)總
是提示說(shuō)沒(méi)有為該文件加載調(diào)試符號(hào)。開(kāi)始還不在意,以為又是代碼和調(diào)試符號(hào)文件不匹配
的原因,折騰了好久,不得其果。
后來(lái)分析了下,發(fā)現(xiàn)這個(gè)調(diào)試提示,就像我開(kāi)著調(diào)試器打開(kāi)了一個(gè)非本工程的代碼文件,而
斷點(diǎn)就打在這個(gè)文件里一樣。也就是說(shuō),VC把我product_a.cpp當(dāng)成不是這個(gè)工程里的代碼
文件。
按照這個(gè)思路寫(xiě)些實(shí)驗(yàn)代碼,最終發(fā)現(xiàn)問(wèn)題所在:VC鏈接器根本沒(méi)鏈接進(jìn)product_a.cpp里
的代碼。表現(xiàn)出來(lái)的情況就是,該編譯單元里的全局常量(全局變量一樣)根本沒(méi)有得到初
始化,因?yàn)槲腋絝actory::register并沒(méi)有被調(diào)用到。為什么VC不鏈接這個(gè)編譯單元對(duì)應(yīng)
的目標(biāo)文件?或者說(shuō),為什么VC不初始化這個(gè)全局常量?
原因就在于,product_a.cpp太獨(dú)立了。一個(gè)在整個(gè)編譯鏈接階段都無(wú)法確定該文件是否被
使用的文件,VC就直接不鏈接了。相反,當(dāng)在factory.cpp里寫(xiě)下類(lèi)似代碼:
void test()
{
product_a obj;
}
雖然說(shuō)test函數(shù)不會(huì)被調(diào)用,一切情況也變得正常了。好了,不扯了,給最后我的結(jié)論:
1、如果靜態(tài)庫(kù)中某個(gè)編譯單元在編譯階段被確認(rèn)為它并沒(méi)有被外部使用,那么當(dāng)這個(gè)靜態(tài)
庫(kù)被鏈接進(jìn)可執(zhí)行文件時(shí),鏈接器忽略掉該編譯單元里的代碼,那么,鏈接器自然也不會(huì)為
該編譯單元里出現(xiàn)的全局變量常量生成初始化代碼(關(guān)于這部分初始化代碼可以閱讀
<linker and loader>一書(shū));
2、上面那條結(jié)論存在一種傳染性,意思是,當(dāng)可執(zhí)行文件里的代碼使用到靜態(tài)庫(kù)中文件A里
的代碼,A里又有地方使用到B里的代碼,那么B依然會(huì)被鏈接。這種依賴性,應(yīng)該可以讓編
譯器在編譯階段就發(fā)現(xiàn)(顯然,上面我舉的例子里,factory只有在運(yùn)行期間才會(huì)依賴到
product_a.cpp里的代碼)