高质量C++/C编程指南-第11章-其它编程履历(1)
11.1 利用const提高函数的结实性
看到const要害字,C++措施员首先想到的大概是const常量。这可不是精采的条件反射。假如只知道用const界说常量,那么相当于把火药仅用于建造鞭炮。const更大的魅力是它可以修饰函数的参数、返回值,甚至函数的界说体。 const是constant的缩写,“恒定稳定”的意思。被const修饰的对象都受到强制掩护,可以防范意外的变换,能提高措施的结实性。所以许多C++措施设计书籍发起:“Use const whenever you need”。
11.1.1 用const修饰函数的参数
假如参数作输出用,岂论它是什么数据范例,也岂论它回收“指针通报”照旧“引用通报”,都不能加const修饰,不然该参数将失去输出成果。
const只能修饰输入参数:
u 假如输入参数回收“指针通报”,那么加const修饰可以防备意外地窜改该指针,起到掩护浸染。
譬喻StringCopy函数:
void StringCopy(char *strDestination, const char *strSource);
个中strSource是输入参数,strDestination是输出参数。给strSource加上const修饰后,假如函数体内的语句试图窜改strSource的内容,编译器将指堕落误。
u 假如输入参数回收“值通报”,由于函数将自动发生姑且变量用于复制该参数,该输入参数原来就无需掩护,所以不要加const修饰。
譬喻不要将函数void Func1(int x) 写成void Func1(const int x)。同理不要将函数void Func2(A a) 写成void Func2(const A a)。个中A为用户自界说的数据范例。
u 对付非内部数据范例的参数而言,象void Func(A a) 这样声明的函数注定效率较量底。因为函数体内将发生A范例的姑且工具用于复制参数a,而姑且工具的结构、复制、析构进程都将耗损时间。
为了提高效率,可以将函数声明改为void Func(A &a),因为“引用通报”仅借用一下参数的别名罢了,不需要发生姑且工具。可是函数void Func(A &a) 存在一个缺点:“引用通报”有大概改变参数a,这是我们不期望的。办理这个问题很容易,加const修饰即可,因此函数最终成为void Func(const A &a)。
以此类推,是否应将void Func(int x) 改写为void Func(const int &x),以便提高效率?完全没有须要,因为内部数据范例的参数不存在结构、析构的进程,而复制也很是快,“值通报”和“引用通报”的效率险些相当。
问题是如此的缱绻,我只好将“const &”修饰输入参数的用法总结一下,如表11-1-1所示。
对付非内部数据范例的输入参数,应该将“值通报”的方法改为“const引用通报”,目标是提高效率。譬喻将void Func(A a) 改为void Func(const A &a)。
对付内部数据范例的输入参数,不要将“值通报”的方法改为“const引用通报”。不然既达不到提高效率的目标,又低落了函数的可领略性。譬喻void Func(int x) 不该该改为void Func(const int &x)。
表11-1-1 “const &”修饰输入参数的法则
11.1.2 用const修饰函数的返回值
u 假如赐与“指针通报”方法的函数返回值加const修饰,那么函数返回值(即指针)的内容不能被修改,该返回值只能被赋给加const修饰的同范例指针。
譬喻函数
const char * GetString(void);
如下语句将呈现编译错误:
char *str = GetString();
正确的用法是
const char *str = GetString();
u 假如函数返回值回收“值通报方法”,由于函数会把返回值复制到外部姑且的存储单位中,加const修饰没有任何代价。
譬喻不要把函数int GetInt(void) 写成const int GetInt(void)。
同理不要把函数A GetA(void) 写成const A GetA(void),个中A为用户自界说的数据范例。
假如返回值不是内部数据范例,将函数A GetA(void) 改写为const A & GetA(void)简直能提高效率。但此时千万千万要小心,必然要搞清楚函数毕竟是想返回一个工具的“拷贝”照旧仅返回“别名”就可以了,不然措施会堕落。见6.2节“返回值的法则”。
u 函数返回值回收“引用通报”的场所并不多,这种方法一般只呈此刻类的赋值函数中,目标是为了实现链式表达。
譬喻
class A
{…
A & operate = (const A &other); // 赋值函数
};
A a, b, c; // a, b, c 为A的工具
…
a = b = c; // 正常的链式赋值
(a = b) = c; // 不正常的链式赋值,但正当
假如将赋值函数的返回值加const修饰,那么该返回值的内容不答允被窜改。上例中,语句 a = b = c仍然正确,可是语句 (a = b) = c 则是犯科的。