算法笔记 C++中const和auto的那些事 HERODING的算法之路

C++中const和auto的那些事

  • 前言
  • 1. const
    • 1.1 const修饰普通类型的变量
    • 1.2 const 修饰指针变量
      • 1.2.1 常量指针
      • 1.2.2 指针常量
      • 1.2.3 指向常量的常指针
      • 1.2.4 三者区别
  • 2. auto
    • 2.1 auto的用法
    • 2.2 auto的注意事项
  • 3. const与auto
  • 4. 总结

前言

最近做题在暴力的时候发现了一个问题,就是在一些数据量很大的时候(游离于内存的超出范围),如果是const auto& 遍历就不会出问题,但是auto或者const auto仍然会超时,所以带着这个疑惑我开始了探索,当然首先还是从const和auto本身开始介绍。


1. const

const 在 C++ 中作用是用来修饰内置类型变量,自定义对象,成员函数,返回值,函数参数。
它允许指定一个语义约束,编译器会强制实施这个约束,允许程序员告诉编译器某值是保持不变的。如果在编程中确实有某个值保持不变,就应该明确使用const,这样可以获得编译器的帮助。

1.1 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;
}

算法笔记 C++中const和auto的那些事 HERODING的算法之路_第1张图片
结果也是很现实的。。。

1.2 const 修饰指针变量

const修饰指针变量应该是特别常见的考点,包括常量指针和指针常量等问题。

1.2.1 常量指针

又称常指针,修饰指针指向的内容,则内容为不可变量,但是指向的地址可以修改。

  1. 常量指针指向的对象不能通过这个指针来修改,可是仍然可以通过原来的声明修改;
  2. 常量指针可以被赋值为变量的地址,之所以叫常量指针,是限制了通过这个指针修改变量的值;
  3. 指针还可以指向别处,因为指针本身只是个变量,可以指向任意地址。

一般的形式是int const* p; const int* p;你可以理解为都是const修饰* p(即地址),这样就好理解了。

1.2.2 指针常量

本质是一个常量,而用指针修饰它。指针常量的值是指针(就像某些变量的数据类型是int型一样),这个值因为是常量,所以不能被赋值。 你可以理解为地址给固定了,不给修改地址了,但是可以修改地址上的值。

  1. 本身是个常量;
  2. 指针本身是常量,指向的地址不可以变化,但是指向的地址所对应的内容可以变化。

一般的形式是int* const p;

1.2.3 指向常量的常指针

定义是指向常量的常指针本身是一个常量,且指向的对象也是常量。

  1. 一个指针常量,指向的是一个指针对象;
  2. 它指向的指针对象且是一个常量,即它指向的对象不能变化。

代码形式是const int* const p;

1.2.4 三者区别

下面是对应的代码,可以更清晰看到它们之间的差别:

//-------常量指针-------
    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,仍然可以通过原来的声明修改值

2. auto

auto可以在声明变量的时候根据变量初始值的类型自动为此变量选择匹配的类型,auto的自动类型推断发生在编译期,所以使用auto并不会造成程序运行时效率的降低。

2.1 auto的用法

用于代替冗长复杂、变量使用范围专一的变量声明。比如:

	for(auto& [a, b] : nums) {
		//...
	}

直接就省去了复杂的迭代器使用的过程。

2.2 auto的注意事项

  1. auto 变量必须在定义时初始化,这类似于const关键字;
  2. 定义在一个auto序列的变量必须始终推导成同一类型;
  3. 定义在一个auto序列的变量必须始终推导成同一类型;
  4. 如果初始化表达式为const或volatile(或者两者兼有),则除去const/volatile语义;
  5. 如果auto关键字带上&号,则不去除const语义;
  6. 初始化表达式为数组时,auto关键字推导类型为指针;
  7. 如果表达式为数组且auto带上&,则推导类型为数组类型;
  8. 函数或模板参数不能被声明为auto;
  9. auto不是一个真正的类型,仅仅是一个占位符,不能使用一些以类型为操作数的操作符,如sizeof或typeid。

3. const与auto

好了,终于说到auto和const的组合了,auto在遍历数组的时候,和const的组合会有这几种形式:

for(auto x : range) // 拷贝元素
for(auto &&x : range)// 修改元素
for(const auto &x : range)// 只读元素(无法修改)

具体的意义标注在了后面,相信大家一看清晰了,所以为了减少拷贝的开销,auto&最好,如果只是读取而不修改,再加上const即可。

4. 总结

以上是我翻阅资料查找到的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

你可能感兴趣的:(笔记,c++,算法,开发语言,程序设计)