我目前在Mac和Linux中面临不同的行为问题。我在文件test_max.cpp
中有以下代码。
#include <iostream>
#include <algorithm>
float func(float a) {
float b = a;
return b;
}
int main() {
float a = 0.6, b = 1;
const auto& a1 = func(a);
const auto& b1 = func(b);
const auto& res1 = std::max(func(a), func(b));
const auto& res2 = std::max(a1, b1);
std::cout << "res1: " << res1 << std::endl;
std::cout << "res2: " << res2 << std::endl;
}
这就是我编译代码的方式。
g++ -std=c++11 -01 -o test_max test_max.cpp && ./test_max
在Mac上,它为res1
和res2
返回的值与1相同。但是,在Linux上,它总是为res1
返回0。我不知道为什么有人可以帮我吗?
答案 0 :(得分:4)
当您在不同的编译器下看到不同的行为时,您很可能处于未定义行为(或可能只是未指定行为)的领域。在这种情况下,未定义的行为来自访问悬空引用(res1
)。
const auto& res1 = std::max(func(a), func(b));
此行将res1
初始化为对std::max
返回值的引用,从而设置了悬挂引用的可能性。先验地,这只是一种可能性;一些看起来相似的线不会创建悬空的引用。要查看的第一个因素是最外部的函数std::max
。如果该函数按值返回(也就是返回一个临时变量),则该临时变量的生存期将延长,以使res1
不会晃晃。但是,情况并非如此,因为它返回一个引用。不仅是任何引用,而且是对其参数之一的引用。不过,只要返回的参数本身不是临时的,就可以了。 {,func()
返回的是值,而不是引用。因此,我们确实处境很糟。
max
的参数是临时参数。max
返回对其参数的引用。这是Lifetime of a temporary @ cppreference.com的第三个项目符号中描述的情况。结果是一个悬空的引用,访问它以打印其值会调用未定义的行为。
可能有趣的是,添加另一个函数调用可以解决未定义的行为:
const auto& res1 = func(std::max(func(a), func(b)));
当然,如果func
不是身份功能,那将改变功能。但是,就未定义行为而言,最外面的func
返回的值是func(b)
返回的临时值的副本。它是一个立即绑定到参考变量的新临时变量,因此其寿命得以延长。一切都很好。
然后,针对该行的更典型的解决方法是删除与号...
嗯,学习运动。