Object Layout in Memory
How C++ objects are arranged in memory: data members, padding, vtables, base class subobjects. Understanding layout is crucial for binary compatibility and optimization.
Objects = members + padding + vtable pointer (if virtual) + base class subobjects (if inheritance)
Simple Class Layout
class Simple {
int a; // 4 bytes
char b; // 1 byte
// 3 bytes padding
double c; // 8 bytes
};
// Total: 16 bytes
// Memory layout:
// [a: 4][b: 1][pad: 3][c: 8]
See Memory Alignment for padding rules.
Empty Classes
class Empty {};
sizeof(Empty); // 1 (not 0!)
// Why? Two objects must have different addresses
Empty arr[2];
// &arr[0] != &arr[1] requires non-zero size
Empty Base Optimization (EBO):
class Base {};
class Derived : Base {
int x;
};
sizeof(Derived); // 4, not 5! (Base optimized away)
Virtual Functions and vtable
class Base {
int data; // 4 bytes
public:
virtual void foo();
};
// Layout: [vptr: 8][data: 4][padding: 4] = 16 bytes
// vtable (separate):
// [ptr to foo()]
vtable pointer (vptr) added as hidden first member.
Object: [vptr][data][padding]
|
v
vtable: [&Base::foo]
Single Inheritance
class Base {
int base_data; // 4 bytes
public:
virtual void foo();
};
class Derived : Base {
int derived_data; // 4 bytes
};
// Layout:
// [vptr: 8][base_data: 4][derived_data: 4][padding: 4] = 20 bytes
// vtable:
// [&Derived::foo or &Base::foo]
Memory:
[Base subobject: vptr, base_data][Derived data]
Multiple Inheritance
class A {
int a;
public:
virtual void fA();
};
class B {
int b;
public:
virtual void fB();
};
class C : public A, public B {
int c;
};
// Layout (simplified):
// [A's vptr][a][B's vptr][b][c]
// ^ ^
// | |
// vtable A vtable B
Two vptrs for two bases with virtual functions!
Virtual Inheritance (Diamond Problem)
class Base {
int base;
public:
virtual void f();
};
class Left : virtual Base {
int left;
};
class Right : virtual Base {
int right;
};
class Bottom : Left, Right {
int bottom;
};
// Layout (complex):
// [Left part][Right part][shared Base][Bottom data]
// Uses vbase pointer to locate shared Base
Virtual base stored separately, accessed via offset.
Inspecting Object Layout
GCC/Clang
# Show class layout
g++ -fdump-lang-class file.cpp
# Or
clang++ -Xclang -fdump-record-layouts file.cpp
MSVC
cl /d1reportAllClassLayout file.cpp
Example Output
class Widget {
char c;
int i;
double d;
};
Output:
*** Dumping AST Record Layout
0 | class Widget
0 | char c
4 | int i
8 | double d
| [sizeof=16, align=8]
Member Access Optimization
// ❌ Poor layout (12 bytes wasted)
struct Poor {
char a; // offset 0
// 7 padding
double b; // offset 8
// 8 padding
char c; // offset 16
// 7 padding
}; // sizeof = 24
// ✅ Optimized (6 bytes wasted)
struct Optimized {
double b; // offset 0
char a; // offset 8
char c; // offset 9
// 6 padding
}; // sizeof = 16
Rule: Order members large → small for minimal padding.
offsetof Macro
#include <cstddef>
struct Point {
int x;
int y;
};
size_t x_offset = offsetof(Point, x); // 0
size_t y_offset = offsetof(Point, y); // 4
See Padding and offsetof for details.
POD and Standard Layout
// POD (Plain Old Data) - C++03
struct POD {
int x;
double y;
// No virtuals, all public, no constructors
};
// Standard Layout - C++11 (more flexible)
struct StandardLayout {
int x;
private:
double y;
public:
StandardLayout() : x(0), y(0.0) {} // OK
// No virtuals, same access for all members
};
static_assert(std::is_standard_layout_v<StandardLayout>);
Standard layout guarantees compatible C layout for first member.
Compiler-Specific Layouts
Different compilers may use different layouts (ABI differences):
class Widget {
virtual void foo();
int data;
};
// GCC/Clang (Itanium ABI): [vptr][data]
// MSVC: may differ in alignment/padding
Controlling Layout
// Explicit packing (GCC/Clang)
struct __attribute__((packed)) Packed {
char c;
int i; // Misaligned!
}; // sizeof = 5 (no padding)
// MSVC
#pragma pack(push, 1)
struct Packed {
char c;
int i;
};
#pragma pack(pop)
⚠️ Warning: Packed structs cause slow/unsafe memory access. See Alignment.
Summary
Objects contain:
vptrtovtable(if virtual functions) - 8 bytes- Data members (in declaration order)
- Padding (alignment)
- Base class subobjects (if inheritance)
- Size formula:
vptr+ members + padding (aligned to largest member) - Multiple inheritance → multiple
vptrs - Virtual inheritance → shared base at end
Use offsetof to query member positions. POD and standard layout types have predictable C-compatible layouts.
// Interview answer:
// "Object layout: members in declaration order plus alignment
// padding. Virtual functions add vptr (8 bytes) pointing to
// vtable. Single inheritance: base subobject first. Multiple
// inheritance: multiple vptrs for multiple bases. Virtual
// inheritance: shared base stored separately. Minimize padding
// by ordering members large to small. Standard layout types
// have C-compatible layout for first member."