More Effective C++——2. 操作符
操作符
條款5:對定制的 “類型轉換函數” 保持警覺
c++允許編譯器在不同類型之間執行隱式轉換。但是部分隱式轉換存在安全性問題,例如 int–>short,
double–>char。然而,自己設計類型時可以嘗試提供特定的 “函數” 來作為隱式類型轉換使用,并保證安
全性。
[!tip]
盡管如此,最好不要提供任何類型轉換函數。
實現定制的類型轉換函數有兩種方案。
1. 單自變量 constructors
單自變量 constructors 指能夠以單一自變量成功調用的 constructors,也可以是擁有多個參數,但除
了第一個參數之外都有默認值。
2. 隱式類型轉換操作符
隱式類型轉換操作符,是一個擁有奇怪名稱的 member function:在關鍵詞 operator 之后加上一個類
型名稱,并且不制定返回值類型。
3. 最好不要提供任何類型轉換函數
因為在未預期的情況下,此類函數可能會被調用,而結果可能不正確,不直觀且難以調試。
a. 隱式類型轉換操作符
針對隱式類型轉換操作符,可能的情況如下:
Rational r(1, 3); std::cout << r; // 期待打印 "1/3"如果 Rational 中并為提供 operator<< 方法,但卻提供了隱式類型轉換操作符,這時就會發生意想不到
的結果。編譯器會將 Rational 轉換為 double 進行打印,這顯然并不是期待的結果。
為了解決這個問題,應當使用一個函數來取代隱式類型轉換操作符,例如 asDouble。
class Rational { public:double asDouble() const; }Rational r(1, 3); std::cout << r; // 期待打印 "1/3" std::cout << r.asDouble() // 期待打印 0.333333b. 單自變量 constructors
通過單自變量的 constructor 完成的隱式轉換是很難消除的。
template<class T> class Array { public:Array(int lowBound, int highBound);Array(int size);T& operator[] (int index); };bool operator==(const Array<int>& lhs, const Array<int>& rhs);Array<int> a(10); Array<int> b(10); for (int i = 0; i < 10; ++i) {if (a == b[i]) { } // 這里寫錯了,所以會造成額外的問題。else { } }上述代碼的一個由于寫錯,所以產生了一個意想不到的問題。我們撰寫這段代碼的本意是,如果 a[i] == b[i]
成立,就做一些事。然而由于寫成了 a,于是編譯器為我們選擇了我們上面寫的這段 operator==。首先,
a 可以匹配 const Array& lhs,那 b[i] 如何匹配后者呢?通過隱式類型轉換,編譯器通過 Array(int size)
的構造方法,將 b[i] 傳入構造出一個臨時對象,這樣就匹配成功了。
為了拒絕這種事情的發生,使用 explicit 關鍵詞,來要求該構造函數必須顯式使用。
template<class T> class Array { public:explicit Array(int size); }; if (a == b[i]) // 非法行為 if (a == Array<int>(b[i])) // 合法行為,但是邏輯錯誤 if (a == static_cast<Array<int>>(b[i])) // 合法,同樣邏輯錯誤 if (a == (Array<int>)b[i]) // 合法,但是邏輯錯誤如果你的編譯器還不支持 explicit 關鍵字,那么你可以使用 proxy class 這種方案進行:
template<class T> class Array { public:class ArraySize {public:ArraySize(int num) : theSize(num) {}int size() const { return theSize; }private:int theSize;}explicit Array(ArraySize size); };if (a == b[i]) // 非法這種類型轉換是不能成功的,因為 num 需要首先隱式轉換為 Array::ArraySize,然后再由 ArraySize
轉換為 Array。這種連續多次轉換的行為是被編譯器禁止的。
條款6:區別 increment/decrement 操作符的 前置 和 后置 形式
為了區分 ++/-- 的前置形式和后置形式,重載函數以參數類型來區分彼此。
class UPInt { // unlimited precision int public:UPInt(int value) : _value(value) {}UPInt &operator++() { // 前置形式(*this)._value += 1;return *this;}const UPInt operator++(int) { // 后置形式UPInt oldValue = *this;++(*this);return oldValue;}UPInt &operator--() {(*this)._value -= 1;return *this;}const UPInt operator--(int) {UPInt oldValue = *this;--(*this);return oldValue;}friend ostream &operator<<(ostream &os, UPInt); private:int _value; };后置式操作符沒有使用傳入的參數,只是為了區別前置式和后置式而已。為了避免發出警告,可以故意省略參
數名稱。前置式返回一個 reference,而后置式返回一個 const 對象。這種行為主要是為了和內建類型保
持一致,以避免錯誤。
除此之外,關于效率問題,顯然 后置式 通過調用 前置式 來完成任務,同時還生成一個臨時對象進行存儲。
因此,前置式效率更高。
[!tip]
選擇的原則是:除非真的需要后置式的行為(返回 const 對象),否則使用前置式。
條款7:千萬不要重載 && || 和 , 操作符
在進行 “真假值” 判斷時,c/c++ 采用“驟死式”的判斷方案,即從左到右進行判斷,如果左面不成立則不繼
續判斷。這使得這三個操作符具有順序性,而對其進行重載會導致破環這種秩序性,從而導致意想不到的結果。
因此應該選擇不去重載這些操作符。
條款8:了解各種不同意義的 new 和 delete
1. new
主要需要理解 new operator 和 operator new 之間的差異。
new operator 是類似于 string *ps = new string("hello world"); 中的new。這個操作符是
由語言內建的,不能被改變。它一般執行兩個操作:1. 分配一個足夠防止類型對象的內存空間。2. 調用一個
constructor,為剛才分配的內存中那個對象設定初值。
operator new 則是用來申請內存空間的函數,通常這樣使用void *rawMemory = operator new(sizeof(string))。
此外,operator new還可以被重載,改變其行為。
需要注意的是,只要使用 new operator,必定會默認重新使用 operator new 來分配一塊空間,并調用
constructor。通常情況下無法直接在一塊已分配的空間上直接調用 constructor。
placement new
如果需要在一些分配好的原始內存中,直接調用 constructor 來構建對象。有一個特殊版本的 operator
new 被成為 placement new,允許你這么做。
2. deletion and Deallocation
與 new operator 和 operator new 的關系一樣,delete operator 和 operator delete 也是
類似卻不同的兩個操作。
delete operator 與 new operator 相對應,它也執行兩步操作:1. 調用對象的 destructor 方法,
從而釋放對象中其他引用的內存空間。2. 執行 operator delete 將申請的空間還給內存。
而 operator delete 與 operator new 相對應,只進行空間的釋放。這也就對使用者提出了新的要求,
必須手動調用對象的 destructor 方法才行。
需要注意的是,不能直接使用 delete operator 來釋放 pw 指針指向的內容,因為該過程并非使用 new
operator 來實現的,而是使用 placement new 來完成的,會產生錯誤。
3. 數組
operator new/delete 也可以處理數組內容,對應的使用方法是
int main() {void *rawMemory = operator new[](sizeof(Widget) * 10);operator delete[](rawMemory); }總結
以上是生活随笔為你收集整理的More Effective C++——2. 操作符的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: NanoVG 优化笔记:性能提高5倍的秘
- 下一篇: 成都瀚德科技C++高级开发工程师(win