C++ const小结

const是C++的精髓。用法很多,学会善用const非常非常重要。

const变量

const可用于修饰变量,表示这个变量不可修改:

const double pi = 3.14;
// double const pi = 3.14; 等效的(const放在前后都可以)

这样一来,x就成为编译器眼里的常量,如果尝试给它赋值编译器就报错。这样后面用到很多次需要修改时,就只用改一个了。它的语义通常是“这个变量是整个程序的全局属性,放在开头方便修改”。

喜欢违背规则是人的本性。如果我非要修改它怎么办?那我可以把他的地址取出来强行修改:

const int a = 3; // 1

main() {
	static const int a = 3; // 2
	const int a = 3; // 3
	int *p = (int *)(&a); //获取a的地址,强行转换修改
	cout << *p << endl;

	*p = 9;
	cout << "modifyed\n";
	cout << *p << endl;
}

测试发现,情况1和2会报错,3则正常运行。这是因为1和2中a定义为const后编译时就被放到了只读区,在运行时无权限修改;而情况3下a成为一个栈变量,所以运行时跟其他变量没区别,不会有限制,仅仅是编译器不让你直接改而已。

以上这些都是作死取常量地址导致的,如果没有取地址又开了些优化的话,编译时有可能并不生成a,而是像define一样直接替换后文。这样时间上会更快,但空间上往往会更大。

const指针与传参

下面再看看const作用到指针和引用的情况

int n = 3;
const int cn = 3;

const int &nn = n;
// int &nn = cn;

int *const p = &n;
const int *p = &n;

引用很简单,跟普通变量没有区别。nn不能赋值(但可以给n赋值一起改变两个),但cn不能绑定给nn,因为const赋值给别人时只能继续加不能消除,不然一个引用就可以去掉常量属性了。

在看指针,指针的*好像有很多拜访方式,但其实就两类:

  • const在*左侧,此时p可以修改,但*p不能修改
  • const在*右侧,此时*p可以修改,但p不能修改,和引用一样,const数不能赋值给这种能修改的指针

多重指针const的通用规则

以二级指针为例,对于多重指针来说也一样。

image

const与成员函数

const的另一个重要用途就是修饰成员函数。给一个函数加上const,表示该对象成员不可被修改:

struct A{
	int a;
	void foo() const {
		//a = 6; 错误!不可修改
	}
};

这种方式好处多多,它的语义即“该函数不修改对象”,让编译器来检查,也方便阅读。

const成员函数的重载

在C++中,两个成员函数如果一个有const另一个没有,那么他们是可以重载的。

class TextBlock{
public:
	const char& operator[](int pos) const {return text[pos];}
	char& operator[](int pos) {return text[pos];}
};

这个重载的意义是什么呢?因为const对象只能调用const函数,所以这样一来,const对象会调用第一个(仅能读),其他对象会调用第二个(支持读写)。

constexpr(C++11)

constexpr关键字是C++11新加入了关键字。用于在某些情况下替代const。在传统C++里,const修饰的量分为两种:编译时常量和运行时常量:

const int a = 5;//编译时常量
void f(int t) {
	const int p = t; //运行时常量
}

显然,编译时常量就是可以在编译器确定值的,反之则是直到运行才能确认,对他们的处理策略是大不相同的。但是有些时候不好判断你的const是那一种,所以constexpr就成为了手动区分他们的工具。

上例中,将a修改为constexpr,通过编译,验证说明a是编译时常量(因为5是);修改b时则报错,说明b不是编译时常量(因为t不是)。

constexpr还可作用给函数:

constexpr int size() {
	return 42;
}
constexpr int scale5(int x) {
	return 5 * x;
}
constexpr int a = scale5(4);
constexpr int b = size();
// constexpr int c = scale5(i);

这样一个函数必须要短小(只能有一条return语句)。如果参数为常量表达式(scale5(4)),那么返回值也为常量。否则会被当做一般函数处理,所以c的赋值是错误的,即constexpr函数不一定返回常量值。

注:这是C++11中的constexpr内容,在后续版本中,constexpr的用法又有了较大的修改。

const会提高效率吗

读一个只读变量和读写变量,没有理由存在效率上的差异。但是在编译的层面上,有意添加const可以为编译器提供更多信息,指示编译器更加大胆的优化(就好比volatile或者restrict一样),所以在特定情况下可以生成更优秀的汇编码,跑得更快。

posted @ 2022-07-11 15:05  Ofnoname  阅读(73)  评论(0编辑  收藏  举报