忘了什麼時候起,腦子裡就存在了這樣的觀點:
1. 局部變數應盡量定義在代碼起始處
2. 局部變數的構造是在進入函數時進行的,其時間與局部變數聲明的位置無關
我記得這個觀點應該來自權威的書籍或某些具有豐富經驗,在我看來就如同凡人眼裏手持法杖、身著華服的法師一般神聖的開發大牛。這個觀點在當時我的看來是如此的權威,以至於素愛折騰的我也在整個大學期間未予質疑。
由於這個特性,我一直以來就有一個疑問,在RAII中,為了保證Critical Section的最小化,豈不是得為此做刻意的函數分割,將Critical Section抽離出來用單獨的函數封裝。
不過,最近我在看log4cplus的代碼時,看到如下的程式碼片段:
do { ::log4cplus::thread::Guard _sync_guard_object(mutex); this->errorHandler = eh;} while (0)
這段代碼讓我對在我腦海裡存在了長久時間的觀點產生了質疑,如果那是對的,那這裡何必用do迴圈來製造一個子域呢?因此我寫了一些代碼測試一下:
#include "stdafx.h"#include <iostream>using namespace std;#define mainSizeof mainclass obj{public: obj() { cout<<"obj construct ..."<<endl; } ~obj() { cout<<"obj destruct ..."<<endl; }};void LocalVarIniTest1(){ cout<<"Local Variable Initial Test Function 1 : do{} "<<endl; int i = 2; do { cout<<"Begin of the loop body ... "<<endl; obj o; cout<<"End of the loop body ..."<<endl; } while (--i); cout<<"End of Function body 1"<<endl<<endl;}void LocalVarIniTest2(){ cout<<"Local Variable Initial Test Function 2 : {} "<<endl; { cout<<"Begin of the loop body ... "<<endl; obj o; cout<<"End of the loop body ..."<<endl; } cout<<"End of Function body 2"<<endl<<endl;}void LocalVarIniTest3(){ cout<<"Local Variable Initial Test Function 3 : if{} "<<endl; if(true) { cout<<"Begin of the loop body ... "<<endl; obj o; cout<<"End of the loop body ..."<<endl; } cout<<"End of Function body 3"<<endl<<endl;}void LocalVarIniTest4(){ cout<<"Local Variable Initial Test Function 4 : no sub range "<<endl; obj o; cout<<"End of Function body 4"<<endl<<endl;}void LocalVarIniTest5(){ obj o; cout<<"Local Variable Initial Test Function 5 : no sub range "<<endl; cout<<"End of Function body 5"<<endl<<endl;}int mainLocalVarIni(){ LocalVarIniTest1(); LocalVarIniTest2(); LocalVarIniTest3(); LocalVarIniTest4(); LocalVarIniTest5(); getchar(); return 1;}
這段程式在VC6上的輸出如下:
Local Variable Initial Test Function 1 : do{}
Begin of the loop body ...
obj construct ...
End of the loop body ...
obj destruct ...
Begin of the loop body ...
obj construct ...
End of the loop body ...
obj destruct ...
End of Function body 1
Local Variable Initial Test Function 2 : {}
Begin of the loop body ...
obj construct ...
End of the loop body ...
obj destruct ...
End of Function body 2
Local Variable Initial Test Function 3 : if{}
Begin of the loop body ...
obj construct ...
End of the loop body ...
obj destruct ...
End of Function body 3
Local Variable Initial Test Function 4 : no sub range
obj construct ...
End of Function body 4
obj destruct ...
obj construct ...
Local Variable Initial Test Function 5 : no sub range
End of Function body 5
obj destruct ...
從輸出可以簡單的得出一些結論:
1. 對象的構造時機取決於它的定義位置,初始化過程不會被編譯器提前或延後。
2. 對象的析構在生命期結束(退出定義域)時由編譯器自動執行。
3. 迴圈體內定義的變數會被初始化和析構多次。
4. 域以{}定義,它可以是函數體,do,while,if等複合陳述式,單獨的{}也同樣可以定義一個子域。
然而,這並非全部,我之前所接觸到的說法不應該是空穴來說或是錯覺,於是找了找,發現它其實來自C,在C語言中,所有的局部變數都必須定義在函數體的起始位置。建立一個.c檔案,然後添加如下代碼,該檔案將編譯失敗。
void fun(){ int a; a = 1; int b; a = 2; b = 2;}
相關的東西似乎還有一些,一時找不到,以後有時間再補充。