條款 03:儘可能使用 const

條款 03:儘可能使用 const

Use const whenever possible

const 修飾指針和常量

char greeting[] = "Hello";
char* p = greeting;    // non-const pointer, non-const data
const char* p = greeting;    // non-const pointer, const data
char const * p = greeting;    // non-const pointer, const data
char* const p = greeting;    // const pointer, non-const data
const char* const p = greeting;    // const pointer, const data

const 修飾迭代器

std::vector<int> vec;

const std::vector<int>::iterator it = vec.begin();    // 效果等同 T* const
*it = 10;    // 可以改變成功
++it;    // 錯誤

std::vector<int>::const_iterator it = vec.begin();    // 效果等同 const T*
*it = 10;    // 錯誤
++it;    // 可以迭代成功

const 修飾函數返回值

class Rational {...};
const Rational operator* (const Rational& lhs, const Rational& rhs);

返回 const 能夠避免下面這種錯誤

Rational a, b, c;
(a * b) = c;    // 錯誤,可能不是預期的

const 成員函數

  • 能夠使 class 接口更加清晰,得知哪個函數會改動對象而哪個不會
  • 使 pass by reference-to-const 成爲可能

const 重載

兩個成員函數如果只是常量性不同,可以被重載

class TextBlock {
public:
    const char& operator[] (std::size_t) const { return text[position]; } // operator[] for const 對象
    char& operator[] (std::size_t) { return text[position]; } // operator[] for non-const 對象
private:
    std::string text;
};

TextBlock tb("Hello");
const TextBlock ctb("Hello");
tb[0] = 'x'; // 沒問題
ctb[0] = 'x'; // 錯誤

bitwise constness 和 logical constness

主張 bitwise constness 的人認爲,一旦成員函數被申明爲 const,就不能改變任何成員變量(除 static),即不更改任意一個 bit。然後這種觀念很容易出現不合理的地方,比如某個對象內包含一個指針,某個 const 成員函數未改變指針但是改變了指針所指的值,雖然符合 bitwise constness,但是導致了反直觀效果。
主張 logical constness 的人認爲,允許 const 成員函數改變某些 bits,但是應該不被客戶端感知,或者說符合預期。如下面獲取一個高速緩存的文本區塊的長度,其中 textLength 和 lengthIsValid 會實時變更,且符合預期,則可以使用 mutable 關鍵字申明可變。

class CTextBlock {
public:
    std::size_t length() const;
private:
    char* pText;
    mutable std::size_t textLength;
    mutable bool lengthIsValid;
};

std::size_t CTextBlock::length const
{
    if (!lengthIsValid) {
        textLength = std::strlen(pText);
        lengthIsValid = true;
    }
    return textLength;
}

當實現等價時,重載時以 non-const 調用 const 避免重複

如果實現 const 和 non-const 兩個版本的函數,代碼會重複冗長,可以重載時以 non-const 調用 const 避免重複,反向則不行。

class CTextBlock {
public:
    const char& operator[] (std::size_t) const { return text[position]; }
    char& operator[] (std::size_t) {
        return const_cast<char&>(static_cast<const TextBlock&>(*this)[position]);
    }
private:
    std::string text;
};

static_cast 將傳入參數轉爲 const TextBlock&,const_cast 將返回值去 const。如果 non-const 版本實現中需要改變成員變量,則不適用。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章