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