Effective C 筆記(3) 條款4分析

2021-07-16 16:13:58 字數 3178 閱讀 3767

這是乙個比較好理解的條款,從剛學習c語言開始,這樣的問題就一直伴隨至今。

對於intdouble這樣的內建型別,需要手動初始化,比如說:

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(靜態儲存週期宣告)

2.declarations of class members not bound to specific instances(物件無關的成員)

函式內部的static物件被稱作local static物件,反之,其他的static物件則是non-local static物件了。要成為static物件的方法有很多,static關鍵字是其特性的說明之一,正如上述1.所說。

書中描述的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而它們被用來 指向多個相同型別的物件 就需要考慮這些物件是否為同乙個。實際上兩個物件來自同乙個繼承體系,它們甚至不需要宣告為相同型別...