gpt4 book ai didi

c++ - Base to Derived To another Base cast in constructor segfault — 无效代码或编译器错误?

转载 作者:行者123 更新时间:2023-12-04 07:16:07 25 4
gpt4 key购买 nike

这段代码有时会在 GCC/Clang 上给我一个段错误或无效的结果。但是,它在 MSVC 和 ICC 上运行良好。我不确定我的代码是否从标准的角度来看是无效的,或者它是否是 GCC/Clang 中的编译器错误。

#include <cstdio>

struct A {
virtual void func() {}
void* junk = nullptr;
};

template<typename T>
struct B {
B() {
T* cp = static_cast<T*>(this);
A* a = cp;
printf("%p\n", a);
}
};

struct C : virtual A, B<C>
{
C() : A(), B<C>() {}
};

int main() {
C c;

A* ptr = &c;
printf("%p\n", ptr);

return 0;
}
Godbolt(Clang)上的一个这样的错误结果。两个指针都是转换为相同基址 A 的结果,因此应该给出相同的地址:
ASM generation compiler returned: 0
Execution build compiler returned: 0
Program returned: 0
0x7fff9fa82608
0x7fff9fa82510
我已经对其进行了调试以了解其背后的根本原因。 static_cast (this) 很好。但是从 T* -> A* 的指针转换需要 vtable 来获取基类的偏移量,因为 A 它是一个虚拟基类。如果你在 Godbolt 上编译这个函数,你可以看到这一点:
A& func(C& c) {
return c;
}
生成的代码:
func(C&):
mov rax, rdi % rax = address of input C object
mov rcx, qword ptr [rdi] % rcx = load vtable of C
add rax, qword ptr [rcx - 24] % rax += offset of virtual base class A
ret
但是,在B的构造函数中,*this对象的vtable并没有设置为类C的vtable,因此当它从vtable中获取虚拟基类A的偏移量时,它会读取一些垃圾值并计算出无效地址为一个。
我很清楚,我也可以将 B 的构造函数修改为: B(A* a) {} ,这样就可以了。但是,这个选项对我来说是不可能的,因为这个例子是一个更大系统的简化版本。
我向 C 添加了另一个虚拟类,它在 ICC 和 MSVC 中仍然可以正常工作:
Compiler explorer

最佳答案

我认为 N4860 [class.cdtor]/1 涵盖了这一点:

For an object with a non-trivial constructor, referring to any non-static member or base class of the object before the constructor begins execution results in undefined behavior.


在此代码中, A* a = cp;指对象的基类 c在构造函数之前 C()已为该对象输入。
相关条款(但不直接适用),[class.cdtor]/3 和 [basic.life]/6。

关于c++ - Base to Derived To another Base cast in constructor segfault — 无效代码或编译器错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68748920/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com