這是乙個比較好理解的條款,從剛學習c語言開始,這樣的問題就一直伴隨至今。
對於int
、double
這樣的內建型別,需要手動初始化,比如說:
int x= 0;
const
char* text="a c-style string";
double d;
cin >> d;//以輸入流的方式初始化
未初始化變數的錯誤,已經很少犯了,畢竟已經身經百戰。
這裡糾正了我以前的誤解,那就是但凡是在建構函式中做的事情就是初始化,然而,書中指出,帶引數的建構函式使用成員初值列表
的做法可謂之初始化,初始化的順序則是以成員初值列中的次序為標準(即使宣告順序不一樣),而在函式體中的賦值操作,只能算作賦值:
class a
//這是初始化
};//***************
class a
//這是賦值
};
其實兩者效果沒差,不過初始化的結果通常是效率更高。
對於預設建構函式來說,依然是使用成員初值列表的方式,讓需要初始化的成員去呼叫各自的預設建構函式,例如:
class b
};class a
};
什麼是non-local static物件
static關鍵字的作用,在cppreference.com寫道:
(參見:c++ keywords:static
)
1.static storage duration with internal linkage specifier(靜態儲存週期宣告)函式內部的static物件被稱作local static物件,反之,其他的static物件則是non-local static物件了。要成為static物件的方法有很多,static關鍵字是其特性的說明之一,正如上述1.所說。2.declarations of class members not bound to specific instances(物件無關的成員)
書中描述的static物件,並不是我們常說的什麼靜態區域性變數,靜態全域性變數什麼的,前者指的是其儲存週期,其壽命從被構造出來到程式結束為止,後者與變數的儲存位置,作用範圍有關。比如書中的例子:
extern filesystem tfs;
是乙個非靜態全域性變數,但是是乙個non-local static 物件。
編譯單元和示例分析
簡單來說,cpp檔案和其包含標頭檔案就是乙個編譯單元。
現在的問題是,如果兩個不同的編譯單元分別包含兩個non-local static物件,並且其中乙個物件的初始化依賴於另外乙個,則這兩個物件的初始化順序是未知的。
舉個例子:
#include
#include "common.h"
test1 t1;
#include
#include "common.h"
test2 t2;
#include
#include "common.h"
using
namespace
std;
int main()
#ifndef _lib_h_
#define _lib_h_
#include
using
namespace
std;
class test2;
extern test2 t2;
class test2
void said()
private:
int value;
};class test1
};#endif
示例中可以看到,test1例項的構造的前提是t2已經構造。first.cpp和second.cpp則是分別對於t1和t2的構造。t1和t2分別是不同編譯單元中的non-local static物件。
#g++ -c -o first.o first.cpp
#g++ -c -o second.o second.cpp
#g++ -c -o last.o last.cpp
#g++ last.o first.o second.o
#./a.out
test1 construct
i am test2 value=0
test2 construct
hello world
#g++ last.o second.o first.o
#./a.out
test2 construct
test1 construct
i am test2 value=100
hello world
如果t2後於t1初始化,那麼結果將是未定義的。
乙個簡單設計將可以消除這個問題:將non-local static物件放到其專屬的函式內,該物件在函式內部也被宣告為static,這些函式返回該物件的引用,這就是c++ 單例模式
的一種常見手法。
因此,對上述示例進行修改,將non-local static物件放到函式內部,並返回乙個物件引用:
test2& getinstance()
此時,我們需要t2物件的時候,使用其專屬的函式,而不是原來的non-local static物件:
class test1
};
這樣就提供了初始化順序的保證,因為對於local static物件來說,這只在函式呼叫的時候才會初始化,並且當沒有初始t1的時候,t2也不會初始化,因而不會引發構造和析構的成本。
1.effective c++
2.3.
effectivec++這本書沒有多厚,但看了兩天下來發現裡面的知識點還是很多,原計畫的是一篇部落格弄懂2-3個條款,看樣子現在不得不視情況而定了,呵呵,加油吧~
《Effective C 》 條款44 條款45
templates可以節省時間和避免 重複。對於類似的classes或functions,可以寫乙個class template或function template,讓編譯器來做剩餘的事。這樣做,有時候會導致 膨脹 code bloat 其二進位製碼帶著重複 或幾乎重複 的 資料,或者兩者。但這時候...
Effective C 55條款速記版(下)
每種轉型的作用如下 1.const cast通常被用來將物件的 常量特性轉除 cast away the constness 它也是唯一由此能力的c style轉型操作符。2.dynamic cast主要用來執行 安全向下轉型 safe downcasting 也就是用來決定某物件是否歸屬繼承體系中...
Effective C 筆記 條款11
為什麼會出現自我賦值呢?不明顯的自我賦值,是 別名 帶來的結果 所謂 別名 就是 有乙個以上的方法指涉物件 一般而言如果某段 操作pointers或references而它們被用來 指向多個相同型別的物件 就需要考慮這些物件是否為同乙個。實際上兩個物件來自同乙個繼承體系,它們甚至不需要宣告為相同型別...