構造/析構/賦值運算
阿新 • • 發佈:2018-07-17
per delete 被調用 拷貝 賦值操作符 fault virtual 主動 函數
一、C++默認編寫的函數
如果類中沒有定義,程序卻調用了,編譯器會產生一些函數:
- default 構造函數
- copy 構造函數
- copy assignment 操作符
- 析構函數(non virtual)
所以寫下:
class Empty { };
就好比寫下:
class Empty {
public:
Empty(){ ... }
Empty(const Empty& rhs) { ... }
~Empty() { ... }
Empty& operator=(const Empty& rhs) { ... }
};
- 這些函數都是public且inline。
- 惟有當這些函數被需要(被調用),它們才會被編譯器創建出來。
- 如果自己構造了構造函數(無論有無參數),編譯器不會產生default構造函數。
- base class如果把拷貝構造函數或者賦值操作符設置為private,不會產生這兩個函數。
- 含有引用成員變量或者const成員變量不產生賦值操作符。
- 編譯器產生的析構函數是個non-virtual。
編譯器可以暗自為類創建default構造函數、copy構造函數、copy assignment操作符,以及析構函數。
二、拒絕編譯器自動生成函數
構造函數與析構函數是每一個類必須有的,但copy構造函數和copy assignment操作符對於某些類是不需要的需要明令禁止。
為了避免編譯器自動生成copy構造函數和copy assignment操作符可以將其聲明為private成員:
class Uncopyable{
private:
Uncopyable(const Uncopyable&);
Uncopyable& operator= (const Uncopyable&);
}
但類中成員函數和友元函數還是可以調用private函數,所以可以專門設計防止拷貝動作的基類(Boost也提供了這個類,名為noncopyable):
class nocopy : private Uncopyable {
...
}
派生類不再聲明copy構造函數和copy assignment操作符。
如果不需要copy構造函數和copy assignment操作符要明令禁止,為駁回編譯器自動(暗自)提供的機能,可將相應的成員函數聲明為private並且不予實現。使用像noncopyable這樣的基類也是一種做法。
三、為多態基類聲明virtual析構函數
1.給多態基類應該主動聲明virtual析構函數
如果多態基類析構函數沒有加聲明為virtual,當指向派生類對象的基類指針調用delete的時候,基類成分通常會被銷毀,而派生類的成分可能還留在堆裏。這可是形成資源泄漏、敗壞之數據結構、在調試器上消費許多時間。2.非多態基類,不要聲明virtual析構函數
當類不企圖被當做基類的時候,不要令其析構函數為virtual。因為實現virtual函數,需要額外的開銷(指向虛函數表的指針vptr)。
多態基類一般包含一個virtual函數,所以一個類裏面有virtual函數則聲明virtual析構函數,沒有virtual則不聲明virtual析構函數。
構造/析構/賦值運算