Я недостаточно знаком с макетом памяти объектов, которые содержат виртуальные базы, чтобы понять, почему следующее выглядит неправильно скомпилированным как clang, так и gcc. Это академическое упражнение, поэтому, пожалуйста, извините за легкомыслие memset()
в конструкторе. Я тестирую с использованием Linux x86-64 с clang 7 и gcc 8.2:
#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
обнулять члены другого базового класса? Я знаю, что макет не определен стандартом, но я ожидаю, что все реализации гарантируют, что конструктор класса не может вмешиваться в члены данных несвязанного класса, даже если используется в множественном наследовании, подобном этому. Или хотя бы предупредить, что что-то подобное может произойти. (новое предупреждение -Wclass-memaccess
от gcc здесь не диагностируется).
Если все сводится к тому, что memset(this, 0, sizeof(A))
является недопустимым в конструкторе, то я ожидаю, что компиляторы либо не смогут скомпилироваться, либо хотя бы предупредят.
Ссылка: https://godbolt.org/z/OSQV1j