Return 来自函数的局部引用
Return a local reference from function
我正在尝试了解这种(奇怪的?)g++ 行为内部发生了什么。
#include <iostream>
using namespace std;
int& f(void) {
int a = 9;
int& b = a;
return a;
}
int main(void) {
int& l = f();
cout << ++l << '\n' << l << '\n';
}
当 returning a
本身并将其绑定到 l
时,我收到警告(引用局部变量)和 seg.fault 如果我从l,但是当 returning b
本身时,我不仅没有得到 seg.fault,而且我可以在 l 的值随机更改之前从 l(我猜是 UB)访问它一次。但是这里到底发生了什么?
这两个return不一样吗? g++ 是否在 return 之后自动将 a's
区域标记为不可用,因此 seg.fault 而由于某种原因允许 b 寿命更长?
不,C++ 编译器不会将区域标记为不可用。
段错误只是未定义行为表现出来的多种方式之一。这实际上是一种更友好的方式,因为它会让您及早注意到它。
你负责一生。如果你弄错了,结果就是未定义的行为。也不例外。不是段错误。 随便什么。
一个可能的症状是“它似乎有效”。另一个是段错误。其他包括文字时间旅行(其中 UB 稍后在程序中使较早的代码表现不同)、您的计算机硬盘驱动器变得不可用、有人获取您的信用卡信息、您的浏览器历史记录通过电子邮件发送到您的联系人列表等。
一些编译器在调试模式下使用位模式标记释放的内存以帮助调试。
您的主要问题是为什么 gcc 在其中一个选项中不发出警告。这两种选择都是未定义的行为,唯一的区别是在一种情况下编译器可以检测到它并警告你。
C++ 标准不需要对未定义的行为进行诊断。来自您的编译器的任何诊断都是额外的好处;尽管现代 C++ 编译器非常聪明,但它们并不总能弄清楚编译后的代码 will result in demons flying out of your nose.
P.S。 gcc 10.2 会针对 return b;
选项发出带有 -O3
选项的警告。只有 -Wall
,gcc 还会发出 a 2nd 未定义行为的警告,你可以自己发现它是什么。
But what exactly happens here?
未定义的行为。
Aren't the two returns identical?
源代码在语法上明显不同。这两个程序没有相同的语义,因为两个程序都没有任何语义,因为两个程序的含义都是未定义的。因此,不能保证程序的行为相同。
Does g++ automatically mark a's area as unusable after the return
也许吧。基于那个观察,我不会假设情况就是这样,但这可能是真的。查看GCC源码确认。
我正在尝试了解这种(奇怪的?)g++ 行为内部发生了什么。
#include <iostream>
using namespace std;
int& f(void) {
int a = 9;
int& b = a;
return a;
}
int main(void) {
int& l = f();
cout << ++l << '\n' << l << '\n';
}
当 returning a
本身并将其绑定到 l
时,我收到警告(引用局部变量)和 seg.fault 如果我从l,但是当 returning b
本身时,我不仅没有得到 seg.fault,而且我可以在 l 的值随机更改之前从 l(我猜是 UB)访问它一次。但是这里到底发生了什么?
这两个return不一样吗? g++ 是否在 return 之后自动将 a's
区域标记为不可用,因此 seg.fault 而由于某种原因允许 b 寿命更长?
不,C++ 编译器不会将区域标记为不可用。
段错误只是未定义行为表现出来的多种方式之一。这实际上是一种更友好的方式,因为它会让您及早注意到它。
你负责一生。如果你弄错了,结果就是未定义的行为。也不例外。不是段错误。 随便什么。
一个可能的症状是“它似乎有效”。另一个是段错误。其他包括文字时间旅行(其中 UB 稍后在程序中使较早的代码表现不同)、您的计算机硬盘驱动器变得不可用、有人获取您的信用卡信息、您的浏览器历史记录通过电子邮件发送到您的联系人列表等。
一些编译器在调试模式下使用位模式标记释放的内存以帮助调试。
您的主要问题是为什么 gcc 在其中一个选项中不发出警告。这两种选择都是未定义的行为,唯一的区别是在一种情况下编译器可以检测到它并警告你。
C++ 标准不需要对未定义的行为进行诊断。来自您的编译器的任何诊断都是额外的好处;尽管现代 C++ 编译器非常聪明,但它们并不总能弄清楚编译后的代码 will result in demons flying out of your nose.
P.S。 gcc 10.2 会针对 return b;
选项发出带有 -O3
选项的警告。只有 -Wall
,gcc 还会发出 a 2nd 未定义行为的警告,你可以自己发现它是什么。
But what exactly happens here?
未定义的行为。
Aren't the two returns identical?
源代码在语法上明显不同。这两个程序没有相同的语义,因为两个程序都没有任何语义,因为两个程序的含义都是未定义的。因此,不能保证程序的行为相同。
Does g++ automatically mark a's area as unusable after the return
也许吧。基于那个观察,我不会假设情况就是这样,但这可能是真的。查看GCC源码确认。