最近做题在暴力的时候发现了一个问题,就是在一些数据量很大的时候(游离于内存的超出范围),如果是const auto& 遍历就不会出问题,但是auto或者const auto仍然会超时,所以带着这个疑惑我开始了探索,当然首先还是从const和auto本身开始介绍。
const 在 C++ 中作用是用来修饰内置类型变量,自定义对象,成员函数,返回值,函数参数。
它允许指定一个语义约束,编译器会强制实施这个约束,允许程序员告诉编译器某值是保持不变的。如果在编程中确实有某个值保持不变,就应该明确使用const,这样可以获得编译器的帮助。
const int a = 10;
int b = a; // 正确
a = 5; // 错误,不能改变
可以看到一旦变量被const修饰,就无法改变其数值了,因为a 被编译器认为是一个常量,其值不允许修改,甚至是你用一个指针指向其地址,试图从底层修改变量a的值都是行不通的,可以看看下面的代码:
#include
using namespace std;
int main() {
const int a = 10;
int *p = (int *)&a;
*p = 8;
cout << a;
return 0;
}
const修饰指针变量应该是特别常见的考点,包括常量指针和指针常量等问题。
又称常指针,修饰指针指向的内容,则内容为不可变量,但是指向的地址可以修改。
一般的形式是int const* p; const int* p;
你可以理解为都是const修饰* p(即地址),这样就好理解了。
本质是一个常量,而用指针修饰它。指针常量的值是指针(就像某些变量的数据类型是int型一样),这个值因为是常量,所以不能被赋值。 你可以理解为地址给固定了,不给修改地址了,但是可以修改地址上的值。
一般的形式是int* const p;
定义是指向常量的常指针本身是一个常量,且指向的对象也是常量。
代码形式是const int* const p;
下面是对应的代码,可以更清晰看到它们之间的差别:
//-------常量指针-------
const int *p1 = &a;
a = 300; //OK,仍然可以通过原来的声明修改值,
//*p1 = 56; //Error,*p1是const int的,不可修改,即常量指针不可修改其指向地址
p1 = &b; //OK,指针还可以指向别处,因为指针只是个变量,可以随意指向;
//-------指针常量-------//
int* const p2 = &a;
a = 500; //OK,仍然可以通过原来的声明修改值,
*p2 = 400; //OK,指针是常量,指向的地址不可以变化,但是指向的地址所对应的内容可以变化
//p2 = &b; //Error,因为p2是const 指针,因此不能改变p2指向的内容
//-------指向常量的常量指针-------//
const int* const p3 = &a;
//*p3 = 1; //Error
//p3 = &b; //Error
a = 5000; //OK,仍然可以通过原来的声明修改值
auto可以在声明变量的时候根据变量初始值的类型自动为此变量选择匹配的类型,auto的自动类型推断发生在编译期,所以使用auto并不会造成程序运行时效率的降低。
用于代替冗长复杂、变量使用范围专一的变量声明。比如:
for(auto& [a, b] : nums) {
//...
}
直接就省去了复杂的迭代器使用的过程。
好了,终于说到auto和const的组合了,auto在遍历数组的时候,和const的组合会有这几种形式:
for(auto x : range) // 拷贝元素
for(auto &&x : range)// 修改元素
for(const auto &x : range)// 只读元素(无法修改)
具体的意义标注在了后面,相信大家一看清晰了,所以为了减少拷贝的开销,auto&最好,如果只是读取而不修改,再加上const即可。
以上是我翻阅资料查找到的const与auto的比较详细的讲解,以及其实很他们并没有多大的关系,只不过是相互配合而已,所以当读者日后看到这样奇怪的组合应该也就见怪不怪了,剖析分解就能够理解了。最后希望读者可以私信或者评价,指出其他需要注意的地方,万分感谢!下面是本文的参考链接:
https://www.cnblogs.com/lizhenghn/p/3630405.html
https://www.runoob.com/w3cnote/cpp-const-keyword.html
https://blog.csdn.net/qq_31930499/article/details/79948906
https://zhuanlan.zhihu.com/p/101432602