Effective C++ const的使用
2022-07-17 # cpp

Effective c++: const的使用

精髓:尽可能的使用const

语法上的问题——const修饰指针和迭代器

指针

如果关键字const出现在星号左边,表示被指物是常量;

如果出现在星号右边,表示指针自身是常量;

如果出现在星号两边,表示被指物和指针两者都是常量。

其中const写在下图两个位置时等价

迭代器

const与函数

const修饰函数的参数和返回值

修饰参数

确保传入的参数不会被改变,多用于修饰一个常引用。

例如:

1
void print(const TextBlock & ctb);

修饰返回值

1.防止误操作修改了返回值

例如将 (a + b) == c的判断错误的写成了(a + b) = c,此时若返回值被const修饰,则可以提示出错误。

2.返回常引用时,防止调用者通过常引用修改原值

例如:

1
const char& operator[] (std: :size t position) const{}
1
2
3
const TextBlock ctb ("world");
std: : cout << ctb [03]; //正确,未修改返回的引用值
ctb[03] = 'a'; //错误,常引用的值不能被修改

const成员函数

为什么要有const成员函数?

const用来标识函数是否会改动对象的值

改善C++程序效率的一个根本办法是以 pass byreference-to-const方式传递对象,而此技术可行的前提是,我们有const成员函数可用来处理取得(并经修饰而成)的const对象。

实质

标识的实质是将成员函数的this指针标识为const

从上图中可以看出,this指针前面有了const进行修饰。

另外const成员函数虽然不能改变对象的值,但是可以改变传入的引用,指针所指向的值,因为不涉及到this指针。

常量性不同的函数的重载

对于同一种函数,常有const和non-const两种形式的重载,例如

对于两种const而言,可能存在如下方这样代码重合度非常高的情况,会造成代码冗余

我们当然可以把重合的代码写进对象内部的一个private函数中,然后让两个函数分别调用。但是这样也还是会造成一些代码冗余。

另一种方案就是对this指针进行转型。用non-const函数的转型后的this指针来调用const函数。并且对返回值解除const限制。

代码如下:

关于两种const概念

bitwise constness

主张成员函数只有在不更改对象的任何成员变量的时候才可以说是const,也就是不更改对象内的任何一个比特。

编译器所执行的即为此种概念下的const。

但也会有许多成员函数虽然不够具有const性质,但也能通过编译器的bitwise测试

例如对象内只存储了一个指针,成员函数不修改对象内存储指针的指向,但可以修改指针指向的值

logical constness

主张成员函数可以修改它所处理对象内的某些bits,只要客户端侦测不出来就可以

如何做?

编译器强制实施bitwise constness,但编写程序时应该使用”概念上的常量性“。

那么什么时候会需要解决这一问题呢?

例如:

1
2
3
4
5
6
7
8
class Test
{
public:
void output() const
{
cout << "Output for test!" << endl;
}
};

对于如下这样一个类。希望可以用它来进行输出,输出的过程不更改函数内部对象的值,自然可以把输出函数设置为const。

但是假如我们需要统计一下函数输出了多少次。

1
2
3
4
5
6
7
8
9
10
11
class Test
{
public:
void output() const
{
cout << "Output for test!" << endl;
times++;//若下面不加mutable会报错
}
private:
mutable int times;//
};

修改为上方所示,如果不加mutable,自然会报错。但是我们又需要告诉调用者调用这个函数与对象的状态无关,所以const自然还是保留比较好。

这个时候我们就可以借助mutable关键字来标注times变量。

计数器times被mutable修饰,那么它就可以突破const的限制,在被const修饰的函数里面也能被修改。

从而实现逻辑上的常量性。