gpt4 book ai didi

c++ - 使用虚拟继承的类似乎允许基类构造函数覆盖另一个基类的成员

转载 作者:塔克拉玛干 更新时间:2023-11-03 02:24:36 27 4
gpt4 key购买 nike

我对包含虚拟基的对象的内存布局不够熟悉,无法理解为什么以下内容似乎被 clang 和 gcc 编译错误。这是一个学术练习,所以请原谅构造函数中 memset() 的轻率。我正在使用带有 clang 7 和 gcc 8.2 的 Linux x86-64 进行测试:

#include <cstring>

struct A {
A() { memset(this, 0, sizeof(A)); }

int i;
char a;
};

struct B { char b = 'b'; };
struct C : virtual B, A {};

char foo() {
C c;
return c.b;
}

当使用 -O2 -Wall -pedantic -std=c++17 编译时,两个编译器都会生成以下没有警告的程序集:

foo():
xor eax, eax
ret

C 更改为不虚拟继承 B 或将 sizeof(A) 更改为 5 或更少调用 memset 都会将编译器的输出更改为返回 'b',正如我所期望的那样:

foo():
mov al, 98 # gcc uses eax directly, here
ret

C 虚拟/非虚拟地从 B 派生时的内存布局是什么,这些编译器是否错误地允许 A的构造函数将不同基类的成员清零?我知道布局不是由标准定义的,但我希望所有实现都能确保类的构造函数不会干扰不相关类的数据成员,即使在像这样的多重继承中使用时也是如此。或者至少警告这样的事情可能会发生。 (gcc 的新 -Wclass-memaccess 警告未在此处诊断)。

如果归结为 memset(this, 0, sizeof(A)) 在构造函数中无效,那么我希望编译器无法编译或至少发出警告。

链接:https://godbolt.org/z/OSQV1j

最佳答案

I am not familiar enough with the memory layout of objects that contain virtual bases

虚拟基类(以及具有虚拟基类的基类子对象)通常不会构造或表示为相同类型的完整对象,这与具有相同布局的任何其他子对象(该基类子对象的每个子对象的相对位置)作为具有相同类型的完整对象:

  • 数组元素
  • 类(class)成员
  • 没有虚基类的非虚基类子对象

它们都像一个完整的对象一样构造和表示。

澄清:尽管基类子对象的构造函数通常与完整对象的构造函数相同,专为基类子对象保留的内存可能小于其正常大小

to understand why the following appears to be compiled incorrectly by both clang and gcc.

您还没有发布任何错误代码生成的证据。

This is an academic exercise, so please excuse the frivolity

这不是轻浮,而是明显错误

memset() in a copy constructor.

这样做会通过覆盖对象来破坏对象。

代码使用了不受支持的操作(在构造期间覆盖了 c2 对象的内存)并且编译器没有警告您您的代码使用了一个对象,其生命周期调用低级内存访问函数 (memset) 结束。在基类的构造函数中结束生命周期是非法的:从技术上讲,当你结束它时生命周期甚至还没有开始。

如果你想通过覆盖一个对象来结束它的生命周期,在构建之后做。

总结:

不保证每个 T 类型的子对象“拥有”sizeof (T) 字节并且可以覆盖那些字节;然而,这对于数组元素和成员是有保证的。

关于c++ - 使用虚拟继承的类似乎允许基类构造函数覆盖另一个基类的成员,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54102890/

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