C++ Aggregate Initialization | Braces for Structs and Arrays

C++ Aggregate Initialization | Braces for Structs and Arrays

이 글의 핵심

Aggregate types are structs/arrays you can brace-initialize member-by-member. Pair this with designated initializers (C++20), value vs default init, and care with non-POD members like std::string.

What is aggregate initialization?

An aggregate is a struct or array (under the standard rules) without user-provided constructors, private/protected non-static data members, virtual functions, etc. You initialize it with a brace list.

struct Point {
    int x;
    int y;
};

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

Why it matters:

  • Brevity: no ctor boilerplate for plain data
  • Safety: explicit member values
  • Readability: definition and initialization stay aligned
// Verbose ctor style
struct Point {
    int x, y;
    Point(int x_, int y_) : x(x_), y(y_) {}
};
Point p(10, 20);

// Aggregate style
struct Point { int x, y; };
Point p = {10, 20};

Aggregate rules (C++17/C++20 oriented)

Roughly, all of the following must hold:

  1. Array or class type (struct/class/union)
  2. No user-provided constructors (compiler-generated defaults OK)
  3. No private/protected non-static data members
  4. No virtual functions
  5. No virtual/private/protected base classes (C++17+: public inheritance allowed)
struct Aggregate1 {
    int x;
    double y;
};

struct Aggregate2 : Aggregate1 {
    int z;  // C++17: public base OK
};

struct NonAggregate1 {
    NonAggregate1() = default;  // if user-defined ctor—breaks aggregate in many cases
    // (actual rules depend on edition—check `is_aggregate`)
};

Check at compile time:

#include <type_traits>

struct Point { int x, y; };

static_assert(std::is_aggregate_v<Point>);

Examples

Structs

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

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

Person p3 = {"Charlie", 35};   // height value-initialized
Person p4 = {"David"};         // age, height value-initialized

Arrays

int arr1[5] = {1, 2, 3, 4, 5};
int arr2[5] = {1, 2};  // rest zero

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

Nested structs

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

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

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

C++20 designated initializers

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

Config cfg = {
    .width = 1920,
    .height = 1080,
    .fullscreen = true
};

Compared to other init forms

SyntaxMeaning (aggregate S)
S a;Default initialization — locals may be indeterminate
S a{};Value initialization — zeros / empty / defaults
S a = {1, 2};Aggregate init (copy-list form)
S a{1, 2};Aggregate + list init

Non-aggregates go through constructors for S a{...}.

C++20 designated initializers (detail)

Use .member = value in declaration order; skipped members are value-initialized. Out-of-order designation is ill-formed in C++ (unlike some C rules).

Pros: field names in code; fewer order mistakes.
Caveats: refactoring member order breaks call sites; non-aggregates need ctors instead.

Default member values

Omitted trailing members use default member initializers if present, otherwise value initialization.

struct Config {
    int width = 800;
    int height = 600;
    bool fullscreen;  // no default
};

Config c1 = {};                 // all filled per rules
Config c2 = {1920};             // width only

Common issues

Order (designated)

Point p = {.x = 10, .y = 20};  // OK
// Point q = {.y = 20, .x = 10};  // error in C++20

Types with constructors

Non-aggregates cannot use pure {...} aggregate init—use ctors.

Inheritance

struct Base { int x; };
struct Derived : Base { int y; };

Derived d = {{10}, 20};

Array bounds

int arr1[5] = {1, 2, 3};
int arr2[] = {1, 2, 3};
// int arr3[2] = {1, 2, 3};  // error

FAQ

Q1: Aggregate conditions?
A: Public members, no user-provided ctor (per rules), no virtuals—see std::is_aggregate.

Q2: Partial omission?
A: Yes; remaining members use defaults or value init.

Q3: Order?
A: Declaration order; designated init must follow declaration order in C++.

Q4: C++20 changes?
A: Designated initializers for aggregates.

Related: List initialization, Value initialization, Default initialization.

One line: Aggregate initialization fills struct/array members directly with braces—simple and explicit.


  • C++ List initialization
  • C++ Value initialization
  • C++ Designated initializers
  • C++ Default initialization

Keywords

C++, aggregate initialization, struct, array, designated initializers.


  • C++ Aggregate types
  • C++ struct vs class
  • C++ array vs vector