我目前在 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。我不知道为什么。有人可以帮助我吗?
最佳答案
当您在不同的编译器下看到不同的行为时,您很可能处于未定义行为的领域(或者可能只是未指定的行为)。在这种情况下,未定义的行为来自于访问悬空引用 (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)
返回的临时值的拷贝。它是一个新的临时变量,立即绑定(bind)到引用变量,因此它的生命周期得到延长。一切都很好。
话又说回来,此行更典型的修复方法是删除&符号...
嗯,学习练习。
关于c++ - Mac 和 Linux 中 C++ 的 const auto& 的不同行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55423740/