Why is there a restriction for a subobject of a base class?

3.9 / 2:

For any object ( except for a subobject of the base class ), the copy type T is trivial, regardless of whether the object has a valid value of type T, the base bytes (1.7) that make up the object can be copied to the char array or without the char sign.

3.9 / 3:

For any trivially copied type T, if two pointers to T point to different objects T obj1 and obj2, where neither obj1 nor obj2 is a subobject of the base class , if the base bytes (1.7) that make up obj1 are copied to obj2, obj2 subsequently it will have the same meaning as obj1.

I understand these rules formally, but I wonder what is the meaning of such restrictions?

+8
c ++ types base-class
source share
2 answers

Base class subobjects can have a padding at the end that will be used by the derived class. Given two classes,

struct A { int a; char b; }; struct B : A { char c; }; 

it is possible that sizeof(A) == sizeof(B) . If they are equal, it should be clear that things break if you just use memcpy to copy subobject A : you cannot prevent reading or even overwriting the value of c .

Your implementation may or may not reuse such add-ons. The real reason for designing an ABI where padding is not reused is to definitely use code that memcpy does not properly use for such subobjects.

The comments provide an example with empty base classes. This is a specific case where current implementations are likely to reuse base class bytes, but this is not the only time this is allowed.

+9
source share

Here's an example of a hang of values ​​due to godliness with a base class and EBO :

 #include <cassert> #include <iostream> struct Base {}; // empty class struct Derived1 : Base { public: int i; }; int main() { // the size of any object of empty class type is at least 1 assert(sizeof(Base) == 1); // empty base optimization applies assert(sizeof(Derived1) == sizeof(int)); Base objBase; Derived1 objDerived; objDerived.i = 42; Base& refToobjDerived = objDerived; char buf[sizeof(Base)]; // 1 std::memcpy(buf, &objBase, sizeof(Base)); // copy objBase to buf // might do something with buf.. std::memcpy(&refToobjDerived, buf, sizeof(Base)); // EBO! I'm overwriting the int value! std::cout << objDerived.i; // Screwed } 

Example

If you create a base class nontrivially copied , the value will not be affected.

Another problem with dedicated hvd may be an additional addition at the end of the base class, which is used to store data belonging to derivatives.

0
source share

All Articles