閱讀《Effective C 》系列

2021-09-06 17:54:53 字數 4256 閱讀 3533

這樣做主要是為了防止記憶體洩漏,見我hexo部落格。

c++的虛析構函式

「自我賦值」發生在物件賦值給自己時:

class widget 

widget w;

...w=w;

a[i]=a[j]; //潛在的自我賦值,如果i和j有相同的值
*px=*py;   //潛在的自我賦值,如果px和py恰好指向同乙個東西
如果遵循條款13和條款14的忠告,你會運用物件來管理資源,而且你可以確定所謂「資源管理物件」在copy發生時有正確的舉措。這種情況下你的賦值操作符或許是「自我賦值安全的」(self-assignment-safe),不需要額外操心。然而如果你嘗試自行管理資源(如果你打算寫乙個用於資源管理的class就得這樣做),可能會掉進「在停止使用資源之前意外釋放了它」的陷阱。

其實從上面例子來看,似乎沒有太大的問題,但假設你簡歷乙個class來儲存乙個指標指向一塊動態分配的點陣圖(bitmap)

class bitmap 

class widget ;

對於每次賦值,我們要考慮到資源管理,即可能會寫出如下的**:

widget&

widget::operator=(const widget& rhs) //乙份不安全的operator=實現版本

這裡自我賦值的問題是,operator=函式內的*this(賦值的目的端)和rhs有可能是同乙個物件。果真如此,delete就不只是銷毀當前物件的bitmap,它也銷毀rhs的bitmap。

可以通過「證同測試」達到「自我賦值」的檢驗目的:

widget& widget::operator=(const widget& rhs)

然而,這個版本不具備「異常安全性」,考慮在「new bitmap」導致異常,它將得到乙個指標指向一塊被刪除的bitmap。

解決辦法:

widget& widget::operator=(const widget& rhs)

class widget ;

widget& widget::operator=(const widget& rhs)

widget& widget::operator=(widget rhs)

swap動作的典型實現:

namespace std 

}

指標與引用看上去完全不同(指標用操作符』*』和』->』,引用使用操作符』.』),但是它們似乎有相同的功能。指標與引用都是讓你間接引用其他物件。你如何決定在什麼時候使用指標,在什麼時候使用引用呢?

直接從**層面說明區別,定義乙個類

class upint ;
字首操作的自增是用類似以下的**:

// 字首形式:增加然後取回值

upint& upint::operator++()

而字尾形式,則是如此:

const upint upint::operator++(int)

字尾的會有個臨時物件的產生,效率高低比較明了。

一般情況下,new operator=先operator new + 後 placement new,前者用於分配儲存空間,後者用於呼叫建構函式初始化所分配的記憶體。

在c++中真正的臨時物件是看不見的,它們不出現在你的源**中。建立乙個沒有命名的非堆(non-heap)物件會產生臨時物件。這種未命名的物件通常在兩種條件下產生:為了使函式成功呼叫而進行隱式型別轉換和函式返回物件時。

臨時物件是有開銷的,所以你應該盡可能地去除它們,然而更重要的是訓練自己尋找可能建立臨時物件的地方

主要有以下兩個地方:

據我所知,c++控制類的一些trick主要包括建構函式設定為private+設定static函式呼叫它們設定友元函式/類

阻止建立某個類的物件,最容易的方法就是把該類的建構函式宣告在類的private域

class cantbeinstantiated ;
class printjob; // forward 宣告

// 參見effective c++條款34

class printer ;

printer& theprinter()

class printer ;

printer& printer::theprinter()

class printer ; // 當需要的物件過多時

// 就使用這個異常類

printer();

~printer();

...private:

static size_t numobjects;

printer(const printer& rhs); // 這裡只能有乙個printer,

// 所以不允許拷貝

}; // (參見effective c++ 條款27)

// obligatory definition of the class static

size_t printer::numobjects = 0;

printer::printer()

繼續執行正常的建構函式;

++numobjects;

}  printer::~printer()

系統自動分配的記憶體是棧記憶體,是由系統自動分配、釋放。程式設計師通過new或malloc操作開闢的記憶體,是堆記憶體,由程式設計師通過**進行分配、釋放

有以上的條件,我們知道,禁止在堆中產生物件,即限制new的功能;要求只在堆中產生物件,即限制系統物件的例項化

讓我們先從必須在堆中建立物件開始說起。為了執行這種限制,你必須找到一種方法禁止以呼叫「new」以外的其它手段建立物件。這很容易做到。非堆物件(non-heap object)在定義它的地方被自動構造,在生存時間結束時自動被釋放,所以只要禁止使用隱式的建構函式和析構函式,就可以實現這種限制。

把這些呼叫變得不合法的一種最直接的方法是把建構函式和析構函式宣告為private。這樣做***太大。沒有理由讓這兩個函式都是private。最好讓析構函式成為private,讓建構函式成為public。處理過程與條款26相似,你可以引進乙個專用的偽析構函式,用來訪問真正的析構函式。客戶端呼叫偽析構函式釋放他們建立的物件。

class upnumber 

...private:

~upnumber();

};

class upnumber ;
靈巧指標是一種外觀和行為都被設計成與內建指標相類似的物件,不過它能提供更多的功能。它們有許多應用的領域,包括資源管理(參見條款9、10、25和31)和重複**任務的自動化(參見條款17和29)

當你使用靈巧指標替代c++的內建指標(也就是dumb pointer),你就能控制下面這些方面的指標的行為:

構造和析構。你可以決定建立靈巧指標時應該怎麼做。通常賦給靈巧指標預設值0,避免出現令人頭疼的未初始化的指標。當指向某一物件的最後乙個靈巧指標被釋放時,一些靈巧指標負責刪除它們指向的物件。這樣做對防止資源洩漏很有幫助。

拷貝和賦值。你能對拷貝靈巧指標或設計靈巧指標的賦值操作進行控制。對於一些型別的靈巧指標來說,期望的行為是自動拷貝它們所指向的物件或用對這些物件進行賦值操作,也就是進行deep copy(深層拷貝)。對於其它的一些靈巧指標來說,僅僅拷貝指標本身或對指標進行賦值操作。還有一部分型別的靈巧指標根本就不允許這些操作。無論你認為應該如何去做,靈巧指標始終受你的控制。

大多數靈巧指標模板看起來都象這樣:

template//靈巧指標物件模板

class smartptr ;

Effective C 閱讀筆記

2019年九月四日 緒論 explicit的用法 用於建構函式,防止出現隱式型別轉換,例子 include using namespace std class object object void dosomething object b int main int argc,char const a...

Effective C 閱讀筆記(1)

關鍵字 explicit 用於告知編譯器,該建構函式可以用於完成隱式型別轉換 implicit type conversation 建議 除非有乙個很好的理由,否則將建構函式申明為 explicit!c 是乙個由多個次語言組成的語言聯邦 c 風格 物件導向的c 泛型c stl c 不同的次語言尤其各...

《effective c 》閱讀筆記 1

之前閱讀一部分 effective c 作為一本被眾多讀者所推薦的書自然有它的獨特的魅力所在。在 過一部分該書的一部分內容之後,不由的覺得該書確實是集c 精華於一身,同時還加以科普了很多相對來說在一般老式課本難以見到的語法和語句,如智慧型指標等用法,並舉出例項將該其與其他語法相對而言的優點凸顯出來。...