【Effective C++】item03: Use const whenever possible.

Use const whenever possible

尽可能使用const

const多才多艺。可以修饰全局、局部变量,或修饰文件、函数或者区块作用域中被声明为static的对象。也可以用来修饰class内部的static和non-static成员变量。

const修饰指针

对于指针,const可以修饰指针所指物,也可以修饰指针本身。

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

记忆方法,当const出现在 * 左侧的时候,表示被指物是常量;当const出现在 * 右侧时,表示的是指针自身是常量。

const修饰函数

  1. 修饰返回值
class Rational
{
private:
    /* data */
public:
    Rational(/* args */) {}
    ~Rational() {}
    friend const Rational operator* (const Rational& lhs, const Rational& rhs);
};

虽然不建议返回const对象,但是有时会避免一种不经意间发生的错误。

Rational a, b, c;
if (a * b = c) { // error: passing 'const Rational' as 'this' argument discards qualifiers
    // todo
}
  1. const成员函数
class Fred {
public:
  void inspect() const;   // This member promises NOT to change *this
  void mutate();          // This member function might change *this
};
void userCode(Fred& changeable, const Fred& unchangeable)
{
  changeable.inspect();   // Okay: doesn't change a changeable object
  changeable.mutate();    // Okay: changes a changeable object
  unchangeable.inspect(); // Okay: doesn't change an unchangeable object
  unchangeable.mutate();  // ERROR: attempt to change unchangeable object
}
  1. const-overloading
class Fred { /*...*/ };
class MyFredList {
public:
  const Fred& operator[] (unsigned index) const;  // Subscript operators often come in pairs
  Fred&       operator[] (unsigned index);        // Subscript operators often come in pairs
  // ...
};

很多人忽视了一个C++的重要特性:两个成员函数如果只是常量性(constness)不同,可以被重载。

通常下标运算符重载成对出现。

void f(MyFredList& a)  // The MyFredList is non-const
{
  // Okay to call methods that inspect (look but not mutate/change) the Fred at a[3]:
  Fred x = a[3];       // Doesn't change to the Fred at a[3]: merely makes a copy of that Fred
  a[3].inspect();      // Doesn't change to the Fred at a[3]: inspect() const is an inspector-method
  // Okay to call methods that DO change the Fred at a[3]:
  Fred y;
  a[3] = y;            // Changes the Fred at a[3]
  a[3].mutate();       // Changes the Fred at a[3]: mutate() is a mutator-method
}
void f(const MyFredList& a)  // The MyFredList is const
{
  // Okay to call methods that DON'T change the Fred at a[3]:
  Fred x = a[3];
  a[3].inspect();
  // Compile-time error (fortunately!) if you try to mutate/change the Fred at a[3]:
  Fred y;
  a[3] = y;       // Fortunately(!) the compiler catches this error at compile-time
  a[3].mutate();  // Fortunately(!) the compiler catches this error at compile-time
}
  1. 物理常量 vs 逻辑常量
    物理常量(physical constness)也称为bitwise constness。物理常量的阵营认为,成员函数不更改对象内的任意一个bit。

而不幸的是,很多成员函数并不十足具备const的性质却能通过bitwise的测试。
比如如下代码,我们有一个类型为char*的成员变量,operator[]不更改pText,于是编译器开心地认为它是bitwise的。

但是,事实上通过以下代码,终究改变了其值。

class TextBlock
{
private:
    /* data */
    char* pText;
    mutable std::size_t textLength;
    // std::size_t textLength;
    mutable bool lengthIsValid;
    // bool lengthIsValid;
public:
    TextBlock(/* args */) {}
    ~TextBlock() {}
    std::size_t length() const;
    char& operator[](std::size_t position) const { // bitwise声明,但是不适当。
        return pText[position];
    }
};
std::size_t TextBlock::length() const
{
    if (!lengthIsValid) {
        textLength = std::strlen(pText);
        lengthIsValid = true;
    }
    return textLength;
}
const TextBlock tb("abcd");
char* pc = & tb[0];
*pc = 'T';

总结

  1. 将某些东西声明为const可帮助编译器侦测出错误用法,推荐使用。
  2. 编译器强制实施bitwise constness,但是编程的时候应该使用“逻辑上的常量性”。

Reference

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值