【C++】用constexpr,constinit,consteval让程序跑的快一点

news/2024/7/24 12:31:49 标签: c++, 开发语言

从C++11加入constexpr关键字开始,到C++20又加入了consteval ,constinit ,有3个const打头的关键字

虽然是以const开头的,不过这3个关键字主要是指示在编译时候的动作,它们都是在编译时就已经被编译程序处理,并非在运行时被机器处理

下面逐一介绍

以下代码在cygwin gcc 11.4 cmake 3.25中调试通过

constexpr

constexpr是在C++11中加入的关键字,它可以使用在函数和变量上,可以让函数或者变量在编译期间直接算出结果
先看一段代码

#include <stdio.h>
int sqr(int n)
{
    return n * n;
}
int main(int x, char**) 
{   
    int r = sqr(2);
    printf("%d",r);
    return 0;
}

以上代码,调用sqr 计算2的平方

看汇编代码
在这里插入图片描述
上述代码每一步都执行了,包括赋值、调用sqr

然后在对sqr前和变量r前加上constexpr,再看使用constexpr修饰后的结果

#include <stdio.h>
constexpr int sqr(int n)
{
    return n * n;
}
int main(int x, char**) 
{   
    constexpr int r = sqr(2);
    printf("%d",r);
    return 0;
}

看汇编代码
在这里插入图片描述
可以看到,sqr并没有被调用,程序在运行前,就已经被编译程序直接计算出了2的平方为4

这就是constexpr的作用,包括constinit,consteval也是这个作用。

不过,这三个关键字,同样的,必须是程序在未运行前,就可以通过计算确定出的值
,只要输入一个已知的值,就一定可以计算出一个值,这样才能用

比如上例改为

constexpr int sqr(int n)
{
    return n * n;
}
int main(int x, char**) 
{   
    constexpr int r = sqr(x);
    printf("%d",r);
    return 0;
}

会报错

 error: ‘x’ is not a constant expression

应为r 被修饰为constexpr ,所以在编译是必须已经可以产生确定的值才行,而sqr传入x是没有办法算出确定的值的,因为X也不确定

同理,代码如下,将sqr的constexpr 去掉

#include <stdio.h>
int sqr(int n)
{
    return n * n;
}
int main(int x, char**) 
{   
    constexpr int r = sqr(2);
    printf("%d",r);
    return 0;
}

同样也会报错

 error: call to non-‘constexpr’ function ‘int sqr(int)’

因为r 是需要一个可以确认的值,但sqr并不是一个可以,立即执行的确认函数

但是反过来没有问题,把变量r前的constexpr 去掉 ,直接传入数值,或者传入一个变量都可以了

#include <stdio.h>
constexpr int sqr(int n)
{
    return n * n;
}
int main(int x, char**) 
{   
    int r = sqr(2);//sqr(x)
    printf("%d",r);
    return 0;
}

生成的汇编,就像一个函数调用了一样
在这里插入图片描述

下面,介绍一下constexpr 修饰变量的操作,有如下代码

int main(int x, char**) 
{   
    int a = 6;
    constexpr int r = a==6?1:2 ;
    printf("%d",r);
    return 0;
}

上述代码应为a不是常量,所以会报错

 the value of ‘a’ is not usable in a constant expression

原因也是应为a的不确定性导致

修改他的方法,有两种
把int a = 6改为const

const int a = 6

或者

constexpr int a = 6;

a变成不可修改的常量,r的值就可以被确定

其次,被constexpr 修饰的变量,是具有const属性的,不能被修改

int main(int x, char**) 
{   
    const int a = 6;
    constexpr int r = a==6?1:2 ;
    r = 3;
    printf("%d",r);
    return 0;
}

报错如下

 error: assignment of read-only variable ‘r’

consteval

constexpr可以使用在函数和变量上,consteval只能使用在函数上,强制为可以计算出结果的函数

上面介绍constexpr 时,如果变量不用constexpr修饰那么调用sqr时,可以传入变量,但是被consteval修饰的函数,就会报错了

#include <stdio.h>
consteval int sqr(int n)
{
    return n * n;
}
int main(int x, char**) 
{   
    int r = sqr(x);
    printf("%d",r);
    return 0;
}

错误

‘x’ is not a constant expression

这说明被consteval修饰的函数,必须一定要能即时计算才行,所以,要改为

int r = sqr(2);

才可以

constinit

和consteval一样,它也是强制在编译时产生结果的,只不过,consteval强制的是函数,constinit强制的变量

constexpr int sqr(int n)
{
    return n * n;
}
constinit int r = sqr(2);

int main(int x, char**) 
{   
    printf("%d",r);
    return 0;
}

以上代码可以顺利编译通过
但是如果,改为如下

int g =1;
constexpr int sqr(int n)
{
    return n * n;
}
constinit int r = sqr(g);

int main(int x, char**) 
{   
    printf("%d",r);
    return 0;
}

编译器将会产生相关两条错误

1.error: the value of 'g' is not usable in a constant expression
2.error: 'constinit' variable 'r' does not have a constant initializer

应为sqr传入了不是常量的数据,导致sqr不能判断出最终r是什么值
如果想让上例通过,需要将g改为常量

constexpr int g =1;
//const int g =1;

这两种都可以

因为constinit修饰的是静态或线程存储期的变量,所以,它不能在局部函数中出现,上例中,如果将

constinit int r = sqr(2);

移入main中会报错

int main(int x, char**) 
{   
    constinit int r = sqr(2);
    printf("%d",r);
    return 0;
}

错误如下

‘constinit’ can only be applied to a variable with static or thread storage duration

和constexpr修饰的变量不一样,constinit修饰的变量只做强制运算,并不会产生const 变量,所以constinit修饰的变量是可以修改的

constexpr int sqr(int n)
{
    return n * n;
}
constinit int r = sqr(2);
int main(int x, char**) 
{   
    r = 9; //可以
    printf("%d",r);
    return 0;
}

总结

从几个例子其实也可一看出来,这三个关键字的作用,都是为了让可以确定的运算结果,在编译时就首页被执行完毕,这样,运行时等于只是操作一个具体的常量,不会在执行多余的运算,也就提高了一点运行速度。也就是说,被这三个关键字修饰的变量或者函数,即使不使用编译器、程序不运行,也能准确的知道他最终的值.这时候才能使用上述三个关键字功能


http://www.niftyadmin.cn/n/5100427.html

相关文章

软件工程与计算总结(十五)详细设计中面向对象方法下的信息隐藏

软件工程与计算总结&#xff08;十三&#xff09;详细设计中的模块化与信息隐藏 之前的博客中&#xff0c;模块需要隐藏的决策主要由“职责的实现”and“实现的变更”两类&#xff0c;在面向对象方法中&#xff0c;需要做到的就是&#xff1a; 封装类的职责&#xff0c;隐藏职…

【学位论文】GB/T 7714-2015引用的快捷操作方法

GB/T 7714-2015《信息与文献参考文献著录规则》于2015年12月1日开始实施&#xff0c;成为了目前国内主流的学位论文引用格式之一。本文介绍一种比较方便简单的引用方法。 7714示例&#xff1a; [1] He K, Gkioxari G, Dollr P, et al. Mask r-cnn[C]//Proceedings of the IEEE …

给ubuntu提提速,获取无上黑魔法魔力

https://rainchan.win/2022/05/15/Clash-tun%E6%A8%A1%E5%BC%8F%E9%85%8D%E7%BD%AE%E6%8C%87%E5%8D%97/

Java应用性能问题诊断技巧

作者&#xff1a;张彦东 参考&#xff1a;https://developer.aliyun.com/ebook/450?spma2c6h.20345107.ebook-index.28.6eb21f54J7SUYc 文章目录 &#xff08;一&#xff09;内存1.内存2.内存-JMX3.内存-Jmap4.内存-结合代码确认问题 &#xff08;二&#xff09;CPU1.CPU-JMX或…

电商数据平台西域根据ID取商品详情API接口采集产品详情数据、价格 、销量数据操作指南

商品详情API接口是一种用于访问和获取商品信息的接口&#xff0c;通常用于连接电商平台和商家应用程序。这个接口可以提供有关商品的各种详细信息&#xff0c;如名称、价格、描述、图片、类别、库存和评价等。它使得开发者能够为平台上的消费者提供更个性化和定制化的购物体验&…

PostGIS轨迹分析——AIS数据删除异常点

点位连成线 select st_makeline(t.the_geom) from (select the_geomfrom pointswhere name = xxxand point_time > 2023-09-01and point_time < 2023-09-03order by point_time

springcloud之项目实战服务治理

写在前面 在这篇文章 我们已经搭建完成了优惠券模块的单体版本&#xff0c;为了向微服务化迈出坚实的一步&#xff0c;这部分来看下服务治理的内容&#xff0c;并在我们的项目中引入服务治理&#xff0c;下面我们就开始吧&#xff01; 源码 。 1&#xff1a;什么是&#xff…

华为云云耀云服务器L实例评测|使用clickhouse-benchmark工具对ClickHouse的性能测试

目录 引言 1 ClickHouse简介 2 利用docker安装ClickHouse 2.1 安装Docker 2.2 下载ClickHouse Docker镜像 2.3 创建ClickHouse容器 2.4 访问ClickHouse 3 创建测试表 4 运行 clickhouse-benchmark 5 分析结果 结语 引言 利用华为云的云耀云服务器L实例&#xff0c…