【问题标题】:Different behavior in const auto& for C++ in Mac and LinuxMac 和 Linux 中 C++ 的 const auto& 中的不同行为
【发布时间】:2019-08-20 18:24:42
【问题描述】:

我目前在 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 上,它为 res1res2 返回相同的值作为 1。但是,在 linux 上,它总是为 res1 返回 0。我不知道为什么。有人可以帮我吗?

【问题讨论】:

  • 请提供minimal reproducible example 以重现您声称的不同行为。
  • 如果定义了__linux__func1func2 可能都返回 0?
  • 只要您拒绝提供minimal reproducible example,您将无法得到有用的回复
  • 不是std::max坏了,而是你没有给我们看的代码
  • func1func2 返回什么?如果它们按值返回,则max_val 可能是一个悬空引用,即 UB。这可以解释行为上的差异

标签: c++ linux macos


【解决方案1】:

当您在不同的编译器下看到不同的行为时,您很可能处于未定义行为的领域(或者可能仅仅是未指定的行为)。在这种情况下,未定义的行为来自访问悬空引用 (res1)。

const auto&amp; res1 = std::max(func(a), func(b));

这一行将res1 初始化为对std::max 返回的任何内容的引用,从而设置了悬空引用的可能性。先验的,这只是一种可能性;一些外观相似的行不会创建悬空引用。首先要看的是最外层的函数std::max。如果该函数按值返回(也就是返回一个临时函数),那么该临时函数的生命周期将会延长,这样res1 就不会悬空。但是,情况并非如此,因为它返回一个引用。不仅仅是任何引用,而是对其参数之一的引用。不过,这很好,只要返回的参数本身不是临时的。唉,func() 按值返回,而不是按引用返回。所以我们的情况确实很糟糕。

  1. max 的参数是临时的。
  2. max 返回对其参数的引用。

这是Lifetime of a temporary@cppreference.com 的第三个要点中描述的情况。结果是一个悬空引用,访问它以打印其值会调用未定义的行为。


有趣的是,添加另一个函数调用可以解决未定义的行为:

const auto& res1 = func(std::max(func(a), func(b)));

当然,如果func 不是身份功能,这将改变功能。但是,就未定义行为而言,最外层func 返回的值是func(b) 返回的临时值的副本。它是一个立即绑定到引用变量的新临时变量,因此它的生命周期得到了延长。一切都很好。

再说一次,此行更典型的解决方法是删除 & 符号...
嗯,学习练习。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-09-23
    • 2012-05-29
    • 2016-08-02
    • 1970-01-01
    • 2011-05-28
    • 1970-01-01
    相关资源
    最近更新 更多