C++ Aggregate Initialization | A Guide to "Aggregate Initialization"

C++ Aggregate Initialization | A Guide to "Aggregate Initialization"

이 글의 핵심

Aggregate initialization in C++: brace lists for structs and arrays, partial init, nested aggregates, and C++20 designated initializers—practical rules and pitfalls.

What is Aggregate Initialization?

An aggregate is a struct or array that has no user-defined constructors, private members, or virtual functions. It can be initialized all at once using curly braces {}. When studied alongside list initialization, value initialization, and designated initialization, it helps clarify the rules of initialization.

struct Point {
    int x;
    int y;
};

Point p = {10, 20};  // Aggregate initialization

Aggregate Conditions

// ✅ Aggregate
struct Aggregate {
    int x;
    double y;
};

// ❌ Non-aggregate
struct NonAggregate {
    int x;
private:
    int y;  // Private member
};

Practical Examples

Example 1: Struct Initialization

struct Person {
    std::string name;
    int age;
    double height;
};

// Aggregate initialization
Person p1 = {"Alice", 30, 165.5};
Person p2{"Bob", 25, 175.0};

// Partial initialization
Person p3 = {"Charlie", 35};  // height is 0.0
Person p4 = {"David"};        // age is 0, height is 0.0

Example 2: Array Initialization

int arr1[5] = {1, 2, 3, 4, 5};
int arr2[5] = {1, 2};  // Remaining elements are 0

// 2D array
int matrix[2][3] = {
    {1, 2, 3},
    {4, 5, 6}
};

Example 3: Nested Structs

struct Address {
    std::string city;
    int zipCode;
};

struct Person {
    std::string name;
    Address address;
};

Person p = {
    "Alice",
    {"Seoul", 12345}
};

std::cout << p.name << std::endl;
std::cout << p.address.city << std::endl;

Example 4: C++20 Designated Initialization

struct Config {
    int width = 800;
    int height = 600;
    bool fullscreen = false;
};

// C++20: Designated initialization
Config cfg = {
    .width = 1920,
    .height = 1080,
    .fullscreen = true
};

Default Values

struct Data {
    int x = 10;      // Default value
    int y = 20;
    int z = 30;
};

Data d1 = {};           // {10, 20, 30}
Data d2 = {100};        // {100, 20, 30}
Data d3 = {100, 200};   // {100, 200, 30}

Common Issues

Issue 1: Order

struct Point {
    int x;
    int y;
};

// ❌ Incorrect order
// Point p = {.y = 20, .x = 10};  // Error in C++20

// ✅ Correct order
Point p = {.x = 10, .y = 20};

Issue 2: Classes with Constructors

// ❌ Non-aggregate
struct NonAggregate {
    int x;
    NonAggregate(int v) : x(v) {}
};

// NonAggregate obj = {10};  // Error

// ✅ Use constructor
NonAggregate obj(10);

Issue 3: Inheritance

// C++17: Aggregates with inheritance are allowed
struct Base {
    int x;
};

struct Derived : Base {
    int y;
};

Derived d = {{10}, 20};  // Base{10}, y=20

Issue 4: Array Size

// ✅ Explicit size
int arr1[5] = {1, 2, 3};

// ✅ Size deduction
int arr2[] = {1, 2, 3};  // Size is 3

// ❌ Exceeding size
// int arr3[2] = {1, 2, 3};  // Error

Comparison of Initialization Methods

struct Point {
    int x, y;
};

// Aggregate initialization
Point p1 = {10, 20};
Point p2{10, 20};

// Constructor call (if constructor exists)
Point p3(10, 20);

// Default initialization
Point p4;  // x and y contain garbage values

Troubleshooting (production)

  • API evolution: Adding a new member to a public aggregate breaks all designated initializers that omitted trailing fields—prefer constructors or builder types for stable ABI-facing structs.
  • Narrowing: Brace initialization can reject narrowing conversions; cast explicitly when you truly need a lossy conversion and document why.
  • Cross-language bindings: Other languages may not mirror C++ aggregate rules; generate explicit constructors for FFI boundaries.
  • Serialization: Round-trip JSON/YAML into aggregates carefully—missing keys vs explicit nulls interact differently with optional fields and default member initializers.

FAQ

Q1: What are the conditions for aggregates?

A:

  • Only public members
  • No constructors
  • No virtual functions

Q2: Can I partially initialize aggregates?

A: Yes. Uninitialized members will be set to 0 or their default values.

Q3: Does order matter?

A: Yes, members must be initialized in the order they are declared.

Q4: What’s new in C++20?

A: Designated initialization is supported.

Q5: How about array sizes?

A: Sizes must be explicitly declared or deduced, but cannot exceed the declared size.

Q6: Where can I learn more about aggregate initialization?

A:

  • “C++ Primer”
  • “Effective C++”
  • cppreference.com

Related Posts: List Initialization, Value Initialization, Designated Initialization, Default Initialization.