C++11 将变量引用为左值。他们真的 "vars" 还是只是 "alias"?
C++11 References variables as lvalues. Are they really "vars" or are only "alias"?
嗯,问题在标题里。
如果我在 C++11 中有以下代码:
int a, b = 20;
int &ra = a;
ra = b;
std::cout << ra << std::endl; //Prints 20
编译器如何处理“ra”,它是创建另一个 var 作为指针,还是只是一个别名,当编译器发现“ra”与说“a”相同时?
是的。和不。呵呵。继续阅读。
这里有两层抽象,您应该尝试理解它们。
语言
当您编写 C++ 时,您是在描述一个程序。您实际上并不是在编写指令让计算机执行。那是编译器的工作。
在您的 C++ 代码中,ra
只是一个别名。它不是一个“对象”。操作引用的语法很少,这是故意的:我们应该将 ra
视为 being a
;它们是同一事物的两个名称。
即使我们深入研究语言,我们也可以观察到这一点。给出以下函数:
int bar = 42;
int& foo()
{
return bar;
}
…表达式foo()
不是引用!这让很多人感到意外。那是“int
类型的左值”。只是 int
,而不是 int&
。它是一个“命名”您最初使用名称 bar
声明的整数的表达式。从概念上讲,它 不是 一个单独的、有指针的东西,语言规则、类型和值类别证明了这一点。
当然,foo()
returns 引用这一事实并没有被忽略:这就是为什么没有复制,以及为什么结果表达式的值类别为 左值而不是右值.
因此,引用类型并不能增强语言使用不同表达式在多个位置引用对象的能力:它们只为 C++ 程序员提供访问权限能力。引用实际上只与声明有关。一旦程序通过了您的引用声明,您就不再真正处理引用了,因为实际上并没有任何诸如“引用”之类的东西。
(不过,有时可以在这里看到“抽象泄漏”;例如,class 成员声明的引用类型几乎 有占用存储空间,并将在我所知道的每个 ABI 中实现为指针。这只是实际需要。)
计算机程序
我指的是您的编译器创建的实际计算机程序。它包含您的目标机器将执行的实际指令。
在这个真实程序中,对于任何访问,可能会也可能不会取消引用指针,并且在内存中的某个地方可能有也可能没有存储对象。该值可能只是嵌入到您的代码中。有些人称之为“优化”,但实际上这只是您的编译器产生了具有您所描述的语义的最佳计算机程序。
这既适用于引用也适用于非引用。在任何合适的“优化”级别,例如,您的 整个真正的程序可能只是将整数 20
发送到 std::cout
机器的代码;那些 int
s 没有理由在执行期间作为对象实际“存在”在任何内存位置,因为您永远不会获取它们的地址或将所述地址传递给其他需要它们通过“共享”的翻译单元链接器的魔力。
因此,如果您真的关心性能,则需要阅读汇编代码以找出实际发生的情况。否则,你不能也不需要预测它。
把它们放在一起……
…没有真正的理由担心您的引用本身是别名还是“变量”,因为编译过程已经完全模糊了这种区别。
嗯,问题在标题里。 如果我在 C++11 中有以下代码:
int a, b = 20;
int &ra = a;
ra = b;
std::cout << ra << std::endl; //Prints 20
编译器如何处理“ra”,它是创建另一个 var 作为指针,还是只是一个别名,当编译器发现“ra”与说“a”相同时?
是的。和不。呵呵。继续阅读。
这里有两层抽象,您应该尝试理解它们。
语言
当您编写 C++ 时,您是在描述一个程序。您实际上并不是在编写指令让计算机执行。那是编译器的工作。
在您的 C++ 代码中,ra
只是一个别名。它不是一个“对象”。操作引用的语法很少,这是故意的:我们应该将 ra
视为 being a
;它们是同一事物的两个名称。
即使我们深入研究语言,我们也可以观察到这一点。给出以下函数:
int bar = 42;
int& foo()
{
return bar;
}
…表达式foo()
不是引用!这让很多人感到意外。那是“int
类型的左值”。只是 int
,而不是 int&
。它是一个“命名”您最初使用名称 bar
声明的整数的表达式。从概念上讲,它 不是 一个单独的、有指针的东西,语言规则、类型和值类别证明了这一点。
当然,foo()
returns 引用这一事实并没有被忽略:这就是为什么没有复制,以及为什么结果表达式的值类别为 左值而不是右值.
因此,引用类型并不能增强语言使用不同表达式在多个位置引用对象的能力:它们只为 C++ 程序员提供访问权限能力。引用实际上只与声明有关。一旦程序通过了您的引用声明,您就不再真正处理引用了,因为实际上并没有任何诸如“引用”之类的东西。
(不过,有时可以在这里看到“抽象泄漏”;例如,class 成员声明的引用类型几乎 有占用存储空间,并将在我所知道的每个 ABI 中实现为指针。这只是实际需要。)
计算机程序
我指的是您的编译器创建的实际计算机程序。它包含您的目标机器将执行的实际指令。
在这个真实程序中,对于任何访问,可能会也可能不会取消引用指针,并且在内存中的某个地方可能有也可能没有存储对象。该值可能只是嵌入到您的代码中。有些人称之为“优化”,但实际上这只是您的编译器产生了具有您所描述的语义的最佳计算机程序。
这既适用于引用也适用于非引用。在任何合适的“优化”级别,例如,您的 整个真正的程序可能只是将整数 20
发送到 std::cout
机器的代码;那些 int
s 没有理由在执行期间作为对象实际“存在”在任何内存位置,因为您永远不会获取它们的地址或将所述地址传递给其他需要它们通过“共享”的翻译单元链接器的魔力。
因此,如果您真的关心性能,则需要阅读汇编代码以找出实际发生的情况。否则,你不能也不需要预测它。
把它们放在一起……
…没有真正的理由担心您的引用本身是别名还是“变量”,因为编译过程已经完全模糊了这种区别。