条款 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 版本实现中需要改变成员变量,则不适用。