Item 4 確定物件使用前已經被初始化

2021-06-26 18:39:46 字數 2971 閱讀 4080

目錄

一.建構函式

二.成員初值列表

三.不同編譯單元的non-local static 物件的初始化

一.建構函式

在c和 c++中, 一些內建型別(其實也就是c++繼承c的內容)是預設不被自動初始化的, 如int ,double 等等, 但在我的gcc 上, int 被預設初始化為0, char 被預設不輸出,

double確顯示來隨機數。

所以,對於一些內建型別,我們保證不出錯的最佳處理方法:永遠在使用物件之前先將它初始化。

對於類這個我們自定義的型別, c++ 提供了多種函式來解決初始化的問題

預設建構函式, 拷貝建構函式,賦值運算子,這些都是為了避免物件未初始化而產生的一些問題。

看看區別

預設建構函式:當類沒有定義任何建構函式的時候, 編譯器將生成乙個預設建構函式

1.c++規定,每個類必須有預設的建構函式,沒有建構函式就不能建立物件。

2.若沒有提供任何建構函式,那麼c++提供自動提供乙個預設的建構函式,該預設建構函式是乙個沒有引數的建構函式,它僅僅負責建立物件而不做任何賦值操作。

3.只要類中提供了任意乙個建構函式,那麼c++就不在自動提供預設建構函式。

} 拷貝建構函式:通過傳遞引數來構造乙個物件。

賦值運算子:通過過載來實現對類的賦值 「 = 」。

來看乙個具體的例子

#include using namespace std;

class sales_item( )

sales_item(const sales_item &obj)

sales_item& operator= (const sales_item &item)

private:

string isbn;

double price;

std::size_t num;

};int main( )

執行結果:

通過上面可以分清了各種建構函式和它們什麼時候呼叫

二.成員初值列表

但是上面所寫建構函式不是最佳的做法

首先分清賦值和初始化, 上面所寫的建構函式是通過賦值。初始化的時間發生的更早, 發生於這些 「成員」 的預設建構函式被自動呼叫之時,

比如說例子中類的

string isbn;
這個成員在建構函式中不是被初始化,而是被賦值為"  " , 賦值前, 它會先呼叫自己的建構函式來初始化string 這個型別,效率會較低。

效率較高的做法是使用初始化列表

sales_item( ): isbn(" "), price(0), num(0) 

sales_item( const string &isbn, const double pri, const int nu): isbn(isbn), price(pri), num(nu)

成員初始化列表避免了上面先呼叫預設建構函式為string賦值,然後在用建構函式賦值低效率的做法。

但對於內建型別int ,double初始化和賦值成本相同。

如果想使用預設建構函式來初始化成員

sales_item( ):isbn( )
這樣isbn就會呼叫預設建構函式

使用成員初值列表另外乙個好處是當我們的成員有const 和 引用時, 他們是不能被賦值的。

三.不同編譯單元的non-local static 物件的初始化

「c++ 對定義於不同編譯單元的non-local static物件的初始化次序並無明確定義」

分析這句話

編譯單元:產出單一目標檔案的原始碼。(單一原始碼檔案加上標頭檔案)

non-local static物件:先說靜態物件包括全域性物件, 命名空間物件和作用域物件, 以及在類,函式,檔案中static修飾的物件。

在函式中的靜態物件稱為區域性靜態物件,其他稱為非區域性靜態物件。

比如第二個檔案中物件初始化會呼叫第乙個檔案的全域性成員物件, 那麼在第二個檔案初始化完之前第乙個檔案被用的物件是否

被初始化了是個問題。我們不能保證它們的初始化次序。

解決方案:(單執行緒,但是在多執行緒中要注意,會有問題)

將每個non-local static 物件搬到自己的專屬函式內,讓這些函式返回乙個引用指向 它所含的物件, 然後使用者呼叫這些函式不直接

涉及這些物件,non-local static 物件被local static物件替換了.

class filesystem ;

filesystem& tfs( )//呼叫頻繁可以設定為inline

替換extern filesystem tfs;

原因:函式內的local static物件會在函式呼叫時被初始化。

總結:1.了解各種建構函式

2.內建型別進行手工初始化。

3.建構函式最好使用成員初值列表, 而不要在建構函式本體內使用賦值操作。初值列列出的成員變數的次序應該和class中宣告次序相同。

4。為避免「跨編譯單元初始化次序」問題, 用local static物件替換non-local static物件

拷貝有兩種:深拷貝,淺拷貝

當出現類的等號賦值時,會呼叫拷貝函式

在未定義顯示拷貝建構函式的情況下,系統會呼叫預設的拷貝函式——即淺拷貝,它能夠完成成員的一一複製。當資料成員中沒有指標時,淺拷貝是可行的。

但當資料成員中有指標時,如果採用簡單的淺拷貝,則兩類中的兩個指標將指向同乙個位址,當物件快結束時,會呼叫兩次析構函式,而導致指標懸掛現象。

所以,這時,必須採用深拷貝。

深拷貝與淺拷貝的區別就在於深拷貝會在堆記憶體中另外申請空間來儲存資料,從而也就解決了指標懸掛的問題。

簡而言之,當資料成員中有指標時,必須要用深拷貝。

(1)確定物件被使用前已經被初始化

在物件使用之前將它初始化,對於無任何成員的內建型別,你必須手工完成此事。例如 int x 0 const char text double d std cin d 以input stream 的方式完成初始化 內建型別以外的任何其他東西,初始化責任落在建構函式身上。確保每乙個建構函式都將物件的每乙個...

確定物件使用前已經初始化

一 中心內容 1 為內建型別物件進行手工初始化,因為c 不保證初始化他們。2 建構函式最好使用成員初始列表,而不要在建構函式本體內使用賦值操作。初始列表列出的成員變數,其排列次序應該和它們在class中的宣告次序相同 3 為免除 跨編譯單元值初始化次序 問題,請以local static物件替換no...

條款04 確定物件在使用前已經被初始化

讀取未初始化的值會造成不明確的行為。例如下面這個建構函式 abentity abentity const std string name,const std string address,const std list phones thename name theaddress address th...