使用constexpr进行全局和局部变量初始化的区别背后的基本原理

时间:2018-09-01 20:16:07

标签: c++

假设我有一个constexpr函数:

constexpr int func() { return 42; }

现在,如果我定义了一个用func()初始化的全局变量,那么可以保证func()将在编译时求值,因为该变量需要静态初始化:

int a = func(); // here, func() will be compile-time evaluated
                // note that a is NOT constexpr

但是,如果我在函数中初始化局部变量,则不能保证func()将在编译时求值:

int foo() {
    int b = func(); // no guarantee that func() will be compile-time evaluated
    return b;
}

我了解,如果我使用constexpr int b = func();,它将在编译时进行评估。但是,这使得b const。如果我以后要修改b怎么办?

这两种情况为什么有区别?

1 个答案:

答案 0 :(得分:1)

将b放入堆栈后,除非使用int b const = foo ();,否则可以对其进行修改。将此类功能标记为constexpr而不是const将没有任何好处。对于现代CPU上的大多数用途而言,constexpr是一种减少启动时间的方法,这对于处理器和内存较慢的智能手机更重要。

对于嵌入式系统,我们使用constexpr将内容轻松放入ROM。另一种方法是制作一个脚本,为您打印出C / C ++代码,但这是一个额外的步骤。您无需在PC /服务器/智能手机上考虑此问题,因为您使用new创建动态内存,但是在大多数嵌入式系统上却无法做到这一点(但是随着微控制器上RAM和ROM的增加,这种情况已经改变了) ),但对于嵌入式系统,您拥有不同类型的内存,因此需要将内容放入RAM或ROM中。在这里上下文是天赐之物,在高性能计算中也是如此,但是const int foo () { return 420; }constexpr foo () { return 420; }之间的编译器没有区别,它们都被一条移动指令所取代,而无需运行O2优化器。

到目前为止,我最喜欢将constexpr用于嵌入式系统是为了确保ROM中只有一个远程过程调用(RPC)标头的副本。另一种方法是使用字符串,字符串可能会也可能不会重复。 constexpr允许您使用可变参数模板来创建除int之外的类型的数组,而int一直很繁琐,需要多个步骤。

C ++优化的黄金法则是不要试图以一种更快的方式来欺骗编译器,而这种方法是15年前别人教你的。相反,您应该指示编译器要执行的操作,打开O2优化,优化的编译器将放弃您的代码,并将其替换为针对该CPU #LikeABoss 优化的版本。不要像我一样,使用指针算法来设计大量的套接字API,并浪费大量时间进行手工优化的代码仅用于O2优化器,然后删除所有您为之骄傲的,有时甚至更好的优化代码。