I am not familiar enough with the memory layout of objects that contain virtual bases 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 of memset()
in a constructor. I am testing using Linux x86-64 with both clang 7 and 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;
}
When compiled with the -O2 -Wall -pedantic -std=c++17
, both compilers produce the following assembly with no warnings:
foo():
xor eax, eax
ret
Changing C
to not inherit B
virtually or changing sizeof(A)
to 5
or less in the call to memset both change the compilers' output to return 'b'
, as I'd expect:
foo():
mov al, 98 # gcc uses eax directly, here
ret
What is the memory layout of C
when it derives from B
virtually/non-virtually, and are these compilers wrong by allowing A
's constructor to zero out members of a different base class? I know the layout isn't defined by the standard, but I would expect all implementations ensure that a class' constructor cannot interfere with data members of an unrelated class, even when used in multiple inheritance like this. Or at least warn that something like this might happen. (gcc's new -Wclass-memaccess
warning isn't diagnosed here).
If it comes down to memset(this, 0, sizeof(A))
being invalid in a constructor, then I'd expect the compilers to either fail to compile or to at least warn.
memset
could be legit in some cases, code might be split in different TU making the check harder or even impossible). – Jarod42memset
is OK when constructing a complete object (or array element or member subobject). – curiousguy