首页 > 编程语言 >C++中const和constexpr关键字解析:常量、函数和指针

C++中const和constexpr关键字解析:常量、函数和指针

时间:2023-05-25 09:36:28浏览次数:29  
标签:const 常量 int C++ constexpr 修饰 表达式

C++中const和constexpr的作用
很多C++的初学者看到const这个关键字的第一反应都是一头雾水,主要是因为const可以出现在很多的位置,以及后面加入的constexpr更是常常感到困惑,今天就为大家一一解释出现它们的含义和以及作用

const关键字
const修饰变量
这是最基本的一种用法,顾名思义,就是将该变量修饰为常量,从而不可以修改。很多的全局变量都是通过常量来进行修饰,需要注意的是,使用const关键字修饰的变量需要立刻初始化

// 修饰局部变量,全局变量,成员变量
const int a = 2;
a = 3; // 错误,表达式必须是可修改的左值,意思就是a是个常量,无法修改

// 还有人习惯这种写法,作用是一样的,看个人喜好即可
int const b = 22;

// 修饰函数参数
void test(const int num) {
num = 3; // 错误,表达式必须是可修改的左值,意思就是参数num是个常量,无法修改
}
修饰指针
虽然指针也是一种变量,不过当const与指针出现在一起的时候,位置的不同会发生不同的作用,所以单独拎出来讲

// 第一种情况:指针常量
int a = 2;
const int *p = &a; // const作用:使其无法通过指针来修改变量
*p = 3; // 错误,表达式必须是可修改的左值
a = 4; // 正确
cout << *p << endl; // 4
// 同样地,有人习惯这种写法,作用是一样的,看个人喜好即可
int const *p2 = &a;

// 第二种情况:常量指针
int a = 2;
int* const p = &a; // const作用:使指针p无法指向其他变量
int b = 3;
p = &b; // 错误,表达式必须是可修改的左值
修饰函数
const用于修饰函数也是最困惑的地方,主要原因在于它可以出现在不同的地方,并且每一个都有不同的含义。接下来为一一为大家解释

// 修饰函数返回值,这种用法毫无意义,它的作用相当于将返回值修饰为了常量,但是返回值是一个将亡值,在返回之后要么赋值给了其他的变量,然后其他变量可以继续修改,要么就随着离开作用域而被释放内存。所以通常不会这么使用。
const int getNum() {
return 3;
}

// 修饰成员函数,通常加在成员函数的末尾,作用声明该成员函数为只读函数,即无法修改任何成员变量的值
class Student {
public:
void test() const {
member = 3; // 错误,表达式必须是可修改的左值,因为member是成员变量,而test函数被const修饰过后无法修改成员变量
int b = 3;
b = 4; // 正确
}

private:
int member = 2;
};

const引用
这是const最常用的一种方式,通常用于函数的参数列表中,因为我们知道在C++中函数参数有3中传递方式,分别是值传递,指针传递(或者叫地址传递),引用传递,前两种在传递时都会发成拷贝行为

指针本身也是一个变量,在32位操作系统下占用4个字节,64位系统占用8个字节,虽然的拷贝成本会低一点,但是在大量的调用过程中也比较可观

所以通常我们采用传递引用的方式,因为引用只是变量的一个别名,不占用内存,所以不会发生拷贝行为。但是引用传递有一个问题,那就是形参可以改变实参的值。所以为了避免意外修改导致实参的值发生改,通常会采用const加上引用的方式传递参数

void test(const Student &s) {
...
}
constexpr关键字
constexpr是C++11中引入的一个关键字,它的作用主要是用来修饰一些函数和变量,使其成为常量表达式,从而在编译器就可以进行计算,进一步提高程序运行期的效率

常量表达式:指的是有一个或多个常量组成的表达式,在实际开发中经常会接触到常量表达式,比如数组长度就必须是一个常量表达式
int arr[5]; // 正确,长度5是由1个常量组成的常量表达式
int arr2[3 + 4]; // 正确,长度3+4是由2个常量组成的常量表达式
int n = 10;
int arr3[n]; // 错误,长度n是由变量构成,不是常量表达式
修饰变量
由此可以看出,只要是常量表达式,我们就可以通过constexpr来进行修饰,从而提高程序的效率,比如下面这样

contexpr int n = 2 + 2; // 正确,2+2是常量表达式,n将会在编译器进行计算
int arr[n] = {11, 22, 33, 44}; // 正确,n是一个常量表达式
cout << arr[2] << endl; // 33
修饰普通函数
constexpr还可以用于修饰函数的返回值,在C++11中被constexpr修饰的函数只能是非void类型的函数,而且必须非常简短,通常只有一句return表达式。不过在后续的C++14/17/20标准中进一步的放宽了这了限制,都可以通过编译了

constexpr int test() {
return 1 + 1;
}
修饰构造函数
constexpr还可以用于修饰自定义类型,不过有一个前提条件,就是该自定义类型具有constexpr修饰的构造函数,并且该构造函数不能有具体实现,否则会编译报错

class Student {
public:
constexpr Student(const char* name, int age) : name_(name), age_(age) {}

void print() const { cout << name_ << ' ' << age_ << '\\n'; }

private:
const char* name_;
int age_;
};

void test() {
constexpr Student s{"zhangsan", 18};
s.print();
}

总结
const可以修饰编译期和运行期的常量,而constexpr只能修饰编译期的常量

const在仍然可以通过const_cast类型转换来修改值,而constexpr是不可以修改的,其实可以将const理解为只读变量更符合其含义

const只能用于非静态成员函数,而constexpr可以和成员,非成员,构造函数一起使用

再有常量表示的场景,尽可能的加上constexpr来让编译期进行计算

但是大面积的constexpr也会面临相应的增加编译时间的风险
————————————————
原文链接:https://blog.csdn.net/2302_76489021/article/details/129199980

 

标签:const,常量,int,C++,constexpr,修饰,表达式
From: https://www.cnblogs.com/im18620660608/p/17430200.html

相关文章

  • C++之constexpr详解
    constexpr表达式是指值不会改变并且在编译过程就能得到计算结果的表达式。声明为constexpr的变量一定是一个const变量,而且必须用常量表达式初始化:constexprintmf=20;//20是常量表达式constexprintlimit=mf+1;//mf+1是常量表达式constexprintsz=size();//之后......
  • constexpr语法
    1.用constexpr修饰变量 1.1const在C++11之前只有const关键字,从功能上来说这个关键字有双重语义:变量只读,修饰常量,举一个简单的例子: voidfunc(constintnum) { constintcount=24; intarray[num];//error,num是一个只读变量,不是常量......
  • constexpr学习
    constexptr和常量表达式常量表达式是指值不会改变并且在编译过程中就能得到计算结果的表达式。编译过程中得到计算结果。字面值属于常量表达式,用常量表达式初始化的const对象也是常量表达式。一个对象(或表达式)是不是常量表达式由它的数据类型和初始值共同决定。(注意!!!)对于这条语......
  • C++11 constexpr:验证是否为常量表达式(长篇神文)
    constexpr是C++11标准新引入的关键字,不过在讲解其具体用法和功能之前,读者需要先搞清楚C++常量表达式的含义。 所谓常量表达式,指的就是由多个(≥1)常量组成的表达式。换句话说,如果表达式中的成员都是常量,那么该表达式就是一个常量表达式。这也意味着,常量表达式一旦确定,其值......
  • CMake入门教程:从零开始构建C/C++项目
    CMake是一个跨平台的自动化构建工具,可以用于构建各种类型的项目,包括*C++、C、Python、Java*等。本文将从零开始,介绍如何使用CMake构建一个简单的C/C++项目安装CMake首先,需要下载并安装CMake。可以从CMake官网下载。如果404NotFound,可以试一下这个国内镜像网址下载地址。创......
  • C++拷贝控制技术
    模板特例如何写忘了拷贝noexcept 如果可以确认不会抛出异常,交换两个指针就行了swap是命名空间里的某个,更改的时候需要加上该命名空间 特例函数怎么写,就这样。inline的位置值得注意"=”运算符重载 两种拷贝一致 不可拷贝的方式编译器会想方设法为我们......
  • c++打卡练习(38)
    求一个范围内的所有素数流程图:伪代码:源代码:#include<iostream>usingnamespacestd;intmain(){ intstart,end,i,j,m=0; cout<<"给定你所要求的素数的范围:"<<endl; cin>>start; cin>>end; cout<<start<<"到"<<end<<"之......
  • CMake入门教程:从零开始构建C/C++项目
    CMake是一个跨平台的自动化构建工具,可以用于构建各种类型的项目,包括C++、C、Python、Java等。本文将从零开始,介绍如何使用CMake构建一个简单的C/C++项目安装CMake首先,需要下载并安装CMake。可以从CMake官网下载。如果404NotFound,可以试一下这个国内镜像网址下载地址。创......
  • 深入浅出 C++ 11 右值引用
    彻底搞清楚:右值引用/移动语义/拷贝省略/通用引用/完美转发——以最短的篇幅,介绍常见误解(什么时候要用move?什么时候不能move?为什么move失败?)和基础知识(为什么右值引用变量是左值?为什么会调用移动构造函数?),一步步解释“为什么/是什么/怎么做”。写在前面如果你还不知道C++11......
  • C++右值引用
    右值引用应该是C++11引入的一个非常重要的技术,因为它是移动语义(Movesemantics)与完美转发(Perfectforwarding)的基石:移动语义:将内存的所有权从一个对象转移到另外一个对象,高效的移动用来替换效率低下的复制,对象的移动语义需要实现移动构造函数(moveconstructor)和移动赋值运算符(mo......