条款03(一):尽可能使用const

127 篇文章 7 订阅
39 篇文章 3 订阅

条款03:尽可能使用const

Use const whenever possible
因为该条款的内容较多,因此分成三章来进行学习记录。

const的基本用法

首先,对于const,它允许你指定一个语义约束,也就是说指定一个不该被改动的对象,而编译器会强制实施这样的约束。

const允许你告诉编译器和其他的程序员:哪些值应该保持不变!

如果一个值确实不应该被改变,就应该利用const的特性来表达出来。

对于const可以修饰的对象:

  • const可以在classes外部修饰global或者namespace作用域中的常量;
  • const可以修饰文件、函数、或区域作用域(block scope)中被声明为static的对象;
  • const可以修饰classes内部的static和non-static成员变量;
  • const可以修饰指针自身、指针所指物,或两者都是/都不是。

当const修饰指针相关的对象时:

char greeting[] = "Hello";
char* p = greeting;					//non-const指针,non-const数据
const char* p = greeting;			//non-const指针,const数据
char* const p = greeting;			//const指针,non-const数据
const char* const p = greeting;		//const指针,const数据

在上面的例子中,可以看出const修饰指针和数据的规则:

  • 如果const出现在星号左边,表示被指物是常量
  • 如果const出现在星号右边,表示指针自身是常量
  • 如果const出现在星号的两边,表示被指物和指针两者都是常量

如果被指物是常量,const既可以写在类型之前,也可以写在类型之后、星号之前,这两种写法的意义是相同的:

void f1(cosnt Widget* pw);//f1获得一个指针,指向一个常量的(不变的)Widget对象
void f2(Widget const * pw);//f2也是一样的

这里总结来说,const所修饰的,始终是紧挨着它的左边的东西。当const出现在最左端时,这是它所修饰的是就是紧挨着它的右边的东西。

STL迭代器的const用法

STL的迭代器里,都是以指针为基础而塑造出来的,因此,迭代器的作用就像一个T*指针
声明迭代器为const, 等价于声明指针为const(即声明一个T* const指针),表示这个迭代器不可以指向其他不同的东西(指针自身是const),但是它所指的东西的值是可以改动的(数据不是const)。
如果你希望迭代器所指的东西不可以被改动(即希望STL模拟一个const T* 指针),则需要的是const_iterator

//以vector容器为例
std::vector<int> vec;
...
const std::vector<int>::iterator iter = vec.begin();//iter的作用像一个T* const
*iter = 10;		//正确的语法,改变iter所指物
//++iter;		//错误的写法,因为在上面的定义中,指针iter是const类型的,不可以被改变

std::vector<int>::const_iterator cIter = vec.begin();//cIter的作用像一个const T*
//*cIter = 10;	//错误的写法,因为此时指针cIter所指的数据是const,即*cIter是const
++cIter;		//正确的语法,改变cIter

函数的const用法

在函数的声明,const也是使用的。
在一个函数的声明内,const可以和函数返回值、各个参数、函数本身(如果是成员函数) 而产生关联。

令函数返回一个常量值,可以降低因为客户错误而造成的意外,而又不至于放弃安全性和高效性。
例子,关于有理数的*operator声明式

class Rational { ... };	//声明有理数
const Rational operator* (const Rational& lhs, const Rational& rhs);

在上面的声明中,要求返回一个const对象,为什么?
假如如果有如下的操作:

Rational a, b, c;
...
(a * b) = c;	//在a * b的结果上调用operator=

有可能这样的写法是因为程序员的笔误:

if(a * b = c)	...	//是想做一个比较操作,而不小心将“==”写成了“=”

对于这种操作——对于各乘积再赋值,是没有任何道理的。如果a,b,c是内置类型,这个操作时直接报错的。
但是Rational是用户自定义类型,一个“良好的用户自定义类型”的特征就是它们避免无端地与内置类型不兼容。
因此,需要将operator* 的回传值声明为const,就可以预防这个“没有任何意义的赋值动作”。

而对于const参数,和local const对象是一样的,在必要使用的时候去使用。除非你需要改动参数或者local对象,否则,尽量将它们声明为const,这样可以避免很多不必要的错误。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值