C++ 中的引用和字面量
reference and literals in C++
我知道 "literals"(c 字符串、int 或其他)存储在某处(显然在只读数据部分 .rodata 中)也许这不准确...
我想了解为什么这段代码会导致运行时错误:
#include <iostream>
using namespace std;
const int& foo()
{
return 2;
}
const char* bar()
{
return "Hello !";
}
int main() {
cout << foo() << endl; // crash
cout << bar() << endl; // OK
return 0;
}
foo returns 对文字的 const 引用 (2) 为什么这会导致崩溃? foo() 的栈中存储的是整数 2 吗?
另请参阅:Why are string literals l-value while all other literals are r-value?
我明白为什么这令人困惑,所以我会尝试将其分解。
第一种情况:
const int& foo()
{
return 2;
}
return 语句创建了一个 临时对象 ,它是文字 2
的 副本 。所以它的地址要么是 non-extant 要么不同于文字 2
的位置(假设文字 2
有一个位置 - 不保证)。
就是那个引用为 returned.
的临时文件
第二种情况:
const char* bar()
{
return "Hello !";
}
return 语句创建了一个 临时对象 ,它是 指针 [=] 的 副本 44=] 到文字 char 数组的 第一个元素 的 地址 。 指针 包含文字数组的实际地址,并且该地址是 returned 通过复制 给调用者。
所以总结一下。第二个之所以有效,是因为 return 语句获取文字 地址 的副本,而不是文字本身的副本。 address 的存储是临时的并不重要,因为 address 在临时保存其值崩溃后仍然指向正确的位置。
这确实非常令人困惑,为了理解发生了什么,必须深入研究语言规范。
但在我们这样做之前,让我提醒您,编译器警告是您的朋友。如果警告级别足够,您在编译示例时应该会看到以下内容:
In function 'const int& foo()': 3 : warning: returning reference to
temporary [-Wreturn-local-addr] return 2; ^
现在,您的第一个示例发生了什么?不能真正获取整数文字的地址,因为它们并不真正作为对象存在。但是,允许将常量引用绑定到文字。当每个人都知道引用类似于指针时,这怎么可能呢?原因是当您将 const 引用绑定到文字时,您并没有真正将它绑定到文字。相反,编译器会创建一个临时变量,并将您的引用绑定到它。该变量是一个对象,尽管是短暂的。一旦你运行returns,临时对象被销毁,你最终得到悬空引用->崩溃。
在第二个示例中,"hello"
是文字,但您没有返回文字 - 您返回的是指向字符串的指针。并且指针仍然有效,因为它指向的字符串仍然有效。
我知道 "literals"(c 字符串、int 或其他)存储在某处(显然在只读数据部分 .rodata 中)也许这不准确...
我想了解为什么这段代码会导致运行时错误:
#include <iostream>
using namespace std;
const int& foo()
{
return 2;
}
const char* bar()
{
return "Hello !";
}
int main() {
cout << foo() << endl; // crash
cout << bar() << endl; // OK
return 0;
}
foo returns 对文字的 const 引用 (2) 为什么这会导致崩溃? foo() 的栈中存储的是整数 2 吗?
另请参阅:Why are string literals l-value while all other literals are r-value?
我明白为什么这令人困惑,所以我会尝试将其分解。
第一种情况:
const int& foo()
{
return 2;
}
return 语句创建了一个 临时对象 ,它是文字 2
的 副本 。所以它的地址要么是 non-extant 要么不同于文字 2
的位置(假设文字 2
有一个位置 - 不保证)。
就是那个引用为 returned.
的临时文件第二种情况:
const char* bar()
{
return "Hello !";
}
return 语句创建了一个 临时对象 ,它是 指针 [=] 的 副本 44=] 到文字 char 数组的 第一个元素 的 地址 。 指针 包含文字数组的实际地址,并且该地址是 returned 通过复制 给调用者。
所以总结一下。第二个之所以有效,是因为 return 语句获取文字 地址 的副本,而不是文字本身的副本。 address 的存储是临时的并不重要,因为 address 在临时保存其值崩溃后仍然指向正确的位置。
这确实非常令人困惑,为了理解发生了什么,必须深入研究语言规范。
但在我们这样做之前,让我提醒您,编译器警告是您的朋友。如果警告级别足够,您在编译示例时应该会看到以下内容:
In function 'const int& foo()': 3 : warning: returning reference to temporary [-Wreturn-local-addr] return 2; ^
现在,您的第一个示例发生了什么?不能真正获取整数文字的地址,因为它们并不真正作为对象存在。但是,允许将常量引用绑定到文字。当每个人都知道引用类似于指针时,这怎么可能呢?原因是当您将 const 引用绑定到文字时,您并没有真正将它绑定到文字。相反,编译器会创建一个临时变量,并将您的引用绑定到它。该变量是一个对象,尽管是短暂的。一旦你运行returns,临时对象被销毁,你最终得到悬空引用->崩溃。
在第二个示例中,"hello"
是文字,但您没有返回文字 - 您返回的是指向字符串的指针。并且指针仍然有效,因为它指向的字符串仍然有效。