pank Asked:2020-12-17 00:15:15 +0000 UTC2020-12-17 00:15:15 +0000 UTC 2020-12-17 00:15:15 +0000 UTC 常量 x 和 &xx 有什么区别? 772 常量 x 和 &xx 有什么区别? #include <iostream> using namespace std; int main() { const int x = 2; const int &xx = 3; cout << x << endl; cout << xx << endl; return 0; } 为什么需要它&? c++ 3 个回答 Voted Best Answer Vlad from Moscow 2020-12-17T01:45:53Z2020-12-17T01:45:53Z 在语义上,这两个声明是不同的。 const int x = 2; const int &xx = 2; 在第一种情况下,声明了一个常量对象,它是用整数文字初始化的。如果它不需要访问对象的内存,它甚至可能不会被分配内存。编译器可以在编译时使用这个 const 对象的值。例如, const int x = 2; int a[x]; 声明的数组的大小在编译时是已知的。 关于本公告 const int &xx = 2; 然后在这里首先为 expression 的值创建一个临时对象2,然后定义一个对该临时对象的引用。这个临时对象在内存中的位置将在程序执行阶段获知。请注意,临时对象本身不是 const。它只是计算由单个操作数(整数文字 2)组成的表达式的结果。 因此,编译器对引用的使用有不同的反应xx。 因此,例如,MS VC 2016 Community 编译器不会编译以下代码片段 const int &xx = 2; int a[xx]; 错误信息 错误 C2131 表达式未由常量 623 定义 正如我所想,MS VC++ 2016 Community 在这种情况下主要关注 C++ 标准对常量表达式的以下规定(5.20 常量表达式,第 2 页) 一个整数或枚举类型的非易失性左值,它引用一个完整的非易失性 const 对象,该对象具有先前的初始化,用常量表达式初始化,或者 请注意,指定必须发生对 const 对象的引用,而初始化上述代码片段的引用的临时表达式不是 const。因此,编译器会发出一条错误消息。 相同的代码片段在 www.ideone.com 上编译成功。这个编译器似乎是基于 C++ 标准的这个条款的另一个子条款 一个非易失性字面量泛左值,它指的是一个非易失性对象,其生命周期开始于 e 的评估; 本子条款没有说明文字临时对象的常量性。它具有文字类型就足够了。 因此,如果您深入研究 C++ 标准并查看编译器的行为,那么差异就会很明显。:) Harry 2020-12-17T00:22:38Z2020-12-17T00:22:38Z const int &xx = 3;是对 type 常量值的引用int。坦率地说,谈论什么是 C++ 中的引用太长了,所以让我们限制在这个简短的回答中,将您发送到相关文献。 引用就像变量的别名,可以这么说。在您的特定情况下,您不能像那样更改值 3 - 它是一个常量,因此,对该值的引用仅作为const int. isnullxbh 2020-12-17T19:12:22Z2020-12-17T19:12:22Z 机器代码级别的差异: gcc6.x // const int x = 2; mov DWORD PTR [rbp-4], 2 // const int &xx = 3; mov eax, 3 mov DWORD PTR [rbp-20], eax lea rax, [rbp-20] mov QWORD PTR [rbp-16], rax 海合会 4.5.x // const int &xx = 3; mov DWORD PTR [rbp-8], 3 lea rax, [rbp-8] mov QWORD PTR [rbp-16], rax 显然,第二条 [ const int &xx = 3;] 指令比第一条更昂贵。你的帽子。 大小为 x 的数组?请。一条汇编程序指令都没有——前提是我们将来不使用它。 一个大小为 xx 的数组,前提是我们不以任何方式使用它。请。 // gcc 6.x - int arr[xx]; // комментарии излишне mov rax, QWORD PTR [rbp-16] mov eax, DWORD PTR [rax] cdqe sub rax, 1 mov QWORD PTR [rbp-24], rax mov rax, QWORD PTR [rbp-16] mov eax, DWORD PTR [rax] cdqe mov r8, rax mov r9d, 0 mov rax, QWORD PTR [rbp-16] mov eax, DWORD PTR [rax] cdqe mov rsi, rax mov edi, 0 mov rax, QWORD PTR [rbp-16] mov eax, DWORD PTR [rax] cdqe sal rax, 2 lea rdx, [rax+3] mov eax, 16 sub rax, 1 add rax, rdx mov edi, 16 mov edx, 0 div rdi imul rax, rax, 16 sub rsp, rax mov rax, rsp add rax, 3 shr rax, 2 sal rax, 2 mov QWORD PTR [rbp-32], rax
在语义上,这两个声明是不同的。
在第一种情况下,声明了一个常量对象,它是用整数文字初始化的。如果它不需要访问对象的内存,它甚至可能不会被分配内存。编译器可以在编译时使用这个 const 对象的值。例如,
声明的数组的大小在编译时是已知的。
关于本公告
然后在这里首先为 expression 的值创建一个临时对象
2,然后定义一个对该临时对象的引用。这个临时对象在内存中的位置将在程序执行阶段获知。请注意,临时对象本身不是 const。它只是计算由单个操作数(整数文字 2)组成的表达式的结果。因此,编译器对引用的使用有不同的反应
xx。因此,例如,MS VC 2016 Community 编译器不会编译以下代码片段
错误信息
正如我所想,MS VC++ 2016 Community 在这种情况下主要关注 C++ 标准对常量表达式的以下规定(5.20 常量表达式,第 2 页)
请注意,指定必须发生对 const 对象的引用,而初始化上述代码片段的引用的临时表达式不是 const。因此,编译器会发出一条错误消息。
相同的代码片段在 www.ideone.com 上编译成功。这个编译器似乎是基于 C++ 标准的这个条款的另一个子条款
本子条款没有说明文字临时对象的常量性。它具有文字类型就足够了。
因此,如果您深入研究 C++ 标准并查看编译器的行为,那么差异就会很明显。:)
const int &xx = 3;是对 type 常量值的引用int。坦率地说,谈论什么是 C++ 中的引用太长了,所以让我们限制在这个简短的回答中,将您发送到相关文献。引用就像变量的别名,可以这么说。在您的特定情况下,您不能像那样更改值 3 - 它是一个常量,因此,对该值的引用仅作为
const int.机器代码级别的差异:
gcc6.x
海合会 4.5.x
显然,第二条 [
const int &xx = 3;] 指令比第一条更昂贵。你的帽子。大小为 x 的数组?请。一条汇编程序指令都没有——前提是我们将来不使用它。
一个大小为 xx 的数组,前提是我们不以任何方式使用它。请。