繁体   English   中英

在旧的 C++ 编译器上的 `* const&` 中令人费解地引入临时

[英]Puzzling introduction of temporary in `* const&` on older C++ compilers

在使用较旧的 C++ 编译器的平台上构建时,我注意到在其他地方运行良好的代码出现了意外行为。 我不确定这是否表明旧编译器存在错误,或者标准发生了一些变化,但我一直在使用 C++11 明确构建。

特别是,较旧的编译器似乎在我不希望它的情况下为* const&使用临时,并且当它的堆栈帧被清理和覆盖时,该临时导致 SIGSEGV。

这是我从原始代码中提取 MWE 的最大努力。 我的问题围绕 class 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;
}

在编译器资源管理器上尝试

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

未注释的C构造函数是我想要使用的构造函数,但它不能正常工作。 如果我将A* a_ptr参数设为 const,我会在 MWE 中得到预期的结果,但在更大的代码库中我不能这样做。 如果我不使用?:在初始化程序中,或者如果我在初始化程序中明确地将a_ptr->iint* const& ,我也会得到预期的结果,但我不明白为什么我必须这样做。

我原以为用int* * 初始化int* const&会很好,但我最好的猜测是?:以某种方式混淆了编译器。 任何人都可以帮助我了解旧的 GCC 和 ICC 编译器在这里是否不正确,或者我是否误解了该语言?

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

The printf output appears mysterious, but in fact is a straightforward consequence of the bug: even the first read of c.b.i_ptr_const_ref (which is of course a reference that is transparently followed) is reading from the dead temporary, but it has yet被覆盖并且仍然包含ai副本 在第一个printf之后,那个 memory 已经被破坏并且恰好保存了一个堆栈地址。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM