2

我阅读了c++11 faq并找到了这句话:

通常我们想要全局或命名空间对象的编译时评估保证,通常是我们想要放置在只读存储中的对象。

我想看看我的编译器(gcc 版本 4.7.2 (Ubuntu/Linaro 4.7.2-2ubuntu1) )是如何工作的,所以我在下面编写代码:

#include <iostream>
using namespace std;
constexpr int add5(int i){ 
        return i+5;    
}
int main(int argc,char*argv[])
{
constexpr int read_only = add5(10);
cout << &read_only <<endl;
return 0;  
}

我以为read-only会出现在 .rodata 部分,但它没有出现。显然人们可能认为编译器做了优化。在这种观点下,我认为几乎每个常量表达式都可以存储在编译器的表中,但不能省略到目标代码中。如果存在退出,则目标代码中应该存在一些常量表达式,以便更好地进行只读存储。

~$: ./constexpr 
0x7fff622addec
~$: cat /proc/3051/maps 
7fff6228e000-7fff622af000 rw-p 00000000 00:00 0                          [stack]

更新:

我不太明白我特别引用粗体部分的句子。
正如下面的评论,read_only是一个局部变量,它将作为上面的结果出现在堆栈中。如果我们不谈论全局数据或命名空间中的内容,那是没有意义的:

#include <iostream>
using namespace std;
constexpr int add5(int i){
        return i+5;
}
constexpr int read_only = add5(10);
int global_int = add5(10);
int main(int argc,char*argv[])
{
cout << &read_only <<endl;
cout << &global_int <<endl;
getchar();
return 0;
}


~$: ./constexpr 
0x4009b8
0x601068
~$: cat /proc/3157/maps 
00400000-00401000 r-xp 00000000 08:09 1200603              /home/shia/constexpr
00600000-00601000 r--p 00000000 08:09 1200603              /home/shia/constexpr
00601000-00602000 rw-p 00001000 08:09 1200603              /home/shia/constexpr

它按我的预期工作。关于用前缀声明的全局变量const

使用 constexpr 声明的变量或数据成员的行为与使用 const 声明一样,只是它需要在使用前进行初始化,并且其初始化程序必须是常量表达式。因此 constexpr 变量始终可以用作常量表达式的一部分

因此,它也应该出现在.rodata部分中。

4

2 回答 2

0

我阅读它的方式constexpr保证了它可以在编译时被评估,但它甚至不一定被评估。

但是,它不保证在不需要时会对其进行评估(即在您的情况下进行优化)。

例如(来自您的链接):

[...] 它们基本上是保存在编译器表中的值,仅在需要时才发送到生成的代码中

于 2013-06-07T13:48:50.517 回答
0

您已经声明了一个局部变量。如果函数是递归的或程序是多线程的,您可以同时拥有其中两个。两个不同的对象不能有相同的地址,因为C++中对对象的定义是一个地址唯一的东西。

如前所述,不能保证constexpr不会在运行时评估变量初始化。编译器可以使用读写内存,add5甚至可以调用全局变量。不过,在这种情况下,这无关紧要。它需要将局部变量放在那里来跳舞,这样它才能有一个正确的地址。

此外,除了性能之外,您(用户)不允许看到在运行时进行初始化的程序与仅在编译时进行评估的程序之间的区别。任何识别它的实验都必然会默认返回运行时评估行为。

如果您不填写其地址,则该要求将不再适用。然后它可以从堆栈中消失,并完全从运行时操作中消失。

于 2013-06-08T01:21:43.810 回答