Memory layout differences in structs

2019-06-22 03:22发布

问题:

I have the following structure in C++

struct A {
  int a;
  double b;
  float c;
}

Is there a difference in memory layout between this struct and one with a function added to it?

struct B {
  int a;
  double b;
  float c;
  void foo();
}
B::foo() { //do stuff }

回答1:

The C++ standard guarantees that memory layouts of a C struct and a C++ class (or struct -- same thing) will be identical, provided that the C++ class/struct fits the criteria of being POD ("Plain Old Data"). So what does POD mean?

A class or struct is POD if:

All data members are public and themselves POD or fundamental types (but not reference or pointer-to-member types), or arrays of such

  • It has no user-defined constructors, assignment operators or destructors
  • It has no virtual functions
  • It has no base classes

So yes in your case, the memory layout is the same.

Source: Structure of a C++ Object in Memory Vs a Struct



回答2:

Is there a difference in memory layout between this struct and one with a function added to it?

It might.

Since A and B are standard layout1, and their common initial sequence consists of every non-static data member2, they are layout-compatible.

The Standard only describe the semantics of an abstract machine, so there is no guarantee an object of type A will be represented in memory as an object of type B, but layout-compatible types tend to be.


1) [class]/7

A standard-layout class is a class that:

  • has no non-static data members of type non-standard-layout class (or array of such types) or reference,
  • has no virtual functions (10.3) and no virtual base classes (10.1),
  • has the same access control (Clause 11) for all non-static data members,
  • has no non-standard-layout base classes, either has no non-static data members in the most derived class and at most one base class with non-static data members, or has no base classes with non-static data members, and
  • has no base classes of the same type as the first non-static data member.

2) [class.mem]/21 & [class.mem]/22

Two standard-layout struct (Clause 9) types are layout-compatible if they have the same number of non-static data members and corresponding non-static data members (in declaration order) have layout compatible types (3.9).



回答3:

It formally depends on your compiler, but a compiler where declaring a non-virtual member function changes the layout of the class would be borderline sabotage. You need this kind of stability to enforce the compatibility on which shared objects rely on every platform.



回答4:

Yes and no...

In your specific case, no. The struct is nothing more than a data container, and the function resides elsewhere. When the function is called, a pointer to the struct is passed as an additional, implicit first parameter that appears as this pointer within the function.

Matter changes, though, if you add a virtual function. Although the C++ standard does not mandate it, vtables are the defacto standard, and the class will receive a pointer to a vtable as very first, but invisible member. You can try this out by printing out the size of an object before and after adding the virtual function.

On the other hand, if the class is virtual already because of inheriting from another class that already has virtual functions, memory layout won't change any more again as there is already a pointer to the vtable included (although it will point to a different location for instances of the sub-class).