看了會(huì)glog使用文檔,很快就被下面的語(yǔ)法形式吸引了,這顆語(yǔ)法糖,真是太完美了。
1
LOG(INFO) << "Found " << num_cookies << " cookies";
2
CHECK(fp->Write(x) == 4) << "Write failed!";
3
符號(hào)“<<”,第一眼就能理解,使用了流對(duì)象重載操作符“<<”的方法。
問(wèn)題是,如果LOG(INFO)實(shí)際上是一個(gè)流對(duì)象的話,那它怎么做到“在禁止輸出日志時(shí)不編譯“<<”右邊的代碼”呢?
要知道LOG4cpplus,可以是用了下面的語(yǔ)法結(jié)構(gòu)才實(shí)現(xiàn)的,依靠最后那個(gè)括號(hào)。glog的語(yǔ)法顯然更勝一籌了。
1
LOG(INFO,"Found" << num_cookies << " cookies");
于是,跟蹤代碼,總于一窺真面目,大為感嘆。翻譯成原始代碼,應(yīng)該這樣的,
1
LogMessage().stream() << "Found " << num_cookies << " cookies";
巧妙之處,就在于LogMessage是一個(gè)類(lèi),LogMessage()生成了一個(gè)臨時(shí)局部對(duì)象,它的生命期僅在這一行代碼范圍內(nèi)。
就是說(shuō),這行結(jié)束的時(shí)候,LogMessage就被析構(gòu),在析構(gòu)函數(shù)中,去執(zhí)行真正的日志輸出。
寫(xiě)上面例子,是為了引出本文真正的主題,利用C++對(duì)象的生命期來(lái)實(shí)現(xiàn)特殊代碼控制流程。
早年,學(xué)習(xí)Basic語(yǔ)言的時(shí)候,聽(tīng)老師說(shuō)了結(jié)構(gòu)化編程中流程控制的三大元素“順序、選擇、循環(huán)”,真以為有了三大元素,便無(wú)所不能了,其他的都是多余的。
但實(shí)際上,一個(gè)例外便是:在一個(gè)作用域開(kāi)始時(shí),執(zhí)行一些代碼;在作用域退出時(shí),執(zhí)行另一些代碼。比如,Win32上的句柄管理,獲取了句柄,最后一定要釋放。
我個(gè)人認(rèn)為,這種流程控制,在現(xiàn)代C++編程中是如此重要,為其提供專(zhuān)門(mén)語(yǔ)法機(jī)制毫不為過(guò)。
然而,C++前輩們用一種可說(shuō)巧妙,也可卑劣的方式,來(lái)處理這個(gè)問(wèn)題,即利用對(duì)象在作用域中的構(gòu)造與析構(gòu)。
說(shuō)它卑劣,是因?yàn)槿绱酥匾奶匦裕贑++教材里是找不到,使它得不到應(yīng)有的重視。
當(dāng)然不管怎么說(shuō),這個(gè)特性是C++優(yōu)于C的極少特例之一。
總結(jié)一下,我們可以在四種對(duì)象作用范圍內(nèi),實(shí)現(xiàn)上述的特殊流程控制:
1. 全局對(duì)象生命期。一般不推薦使用全局變量,沒(méi)有多少實(shí)際意義;
2. 類(lèi)成員變量,即類(lèi)生命期。最典型的就是智能指針了。
3.局部變量,即函數(shù)中的塊作用域。這是最普遍的,比如什么互斥量守護(hù),資源句柄守護(hù)等等。
4.局部匿名變量(不知道是否該這樣命名),在代碼行的作用域。這很少見(jiàn),glog算是見(jiàn)到的第一個(gè)了。