在较早的C ++编译器上,令人困惑的`* const&`中的临时说明

问题描述 投票:2回答:1

[在使用较旧的C ++编译器的平台上构建时,我注意到代码在其他地方工作正常时出现了意外行为。我不确定这是否表示较旧的编译器中存在错误,还是标准有所更改,但我已经使用C ++ 11进行了显式构建。

尤其是,当我不期望使用较旧的编译器时,似乎* const&使用了一个临时变量,当清理并覆盖了它的堆栈框架时,该临时变量导致了SIGSEGV。

这是我从原始代码中提取MWE的最大努力。我的问题围绕类C的构造函数:

#include <stdio.h>

struct A {
    int* i;
};

class B {
public:
    int* const& i_ptr_const_ref; // normally not public
    B(int* const& i_ptr) : i_ptr_const_ref(i_ptr) {}
    operator int* const& (void) const { return i_ptr_const_ref; }
};

int null_b = { 0 };
int* null_b_ptr = &null_b;
int* const& null_b_ptr_const_ref = null_b_ptr;

class C {
public:
    B b;
//  C(const A* a_ptr) : b(a_ptr ? a_ptr->i : null_b_ptr_const_ref) {} // this works
    C(A* a_ptr) : b(a_ptr ? a_ptr->i : null_b_ptr_const_ref) {} // this fails
//  C(A* a_ptr) : b(a_ptr ? (int* const&) a_ptr->i : null_b_ptr_const_ref) {} // this works
//  C(A* a_ptr) : b(a_ptr->i) {} // this works
};

int main(void) {
    A a;
    A* a_ptr = &a;
    a_ptr->i = (int*) 42;
    C c(a_ptr);
    printf("c.b.i_ptr_const_ref = %p\n", (void*) c.b.i_ptr_const_ref);
    printf("c.b=                  %p\n", (void*) c.b);
    printf("a_ptr->i=             %p\n", (void*) a_ptr->i);
    return 0;
}

Try it on Compiler Explorer

我打印出的值应该全部匹配,但是在5.1之前的GCC编译器和18之前的ICC编译器上(我知道英特尔以与其他编译器的“逐个bug”兼容性而感到自豪),中间显示堆栈地址而不是预期值。我能够尝试的所有Clang和ELLCC编译器版本都能正常运行。

未注释的C构造函数是我要使用的构造函数,但无法正常工作。如果使A* a_ptr参数为const,我会在MWE中获得预期的结果,但是在较大的代码库中,我无法做到这一点。如果不在初始化程序中使用?:,或者在初始化程序中将a_ptr->i显式转换为int* const&,我也会得到预期的结果,但是我不明白为什么必须这样做。

我本以为用int* const&初始化int*会很好,但是我最好的猜测是?:在某种程度上使编译器感到困惑。有人可以帮助我了解较早的GCC和ICC编译器在这里是否不正确,还是我误会了某些语言?

c++ icc gcc4
1个回答
0
投票

这显然是一个编译器错误:当然,可以将类型为int*的左值隐式转换为int* const&,因此条件运算符的结果应为左值。

printf输出看起来很神秘,但实际上是该错误的直接结果:即使是对c.b.i_ptr_const_reffirst读取(当然也是透明地遵循的引用)也正在从死信中读取。临时的,但尚未被覆盖,并且仍然包含a.icopy。在第一个printf之后,该内存已被清除,恰好保留了堆栈地址。

© www.soinside.com 2019 - 2024. All rights reserved.