Coming Soon
This lesson is currently being developed
Struct aggregate initialization
Initialize structs with brace initialization.
What to Expect
Comprehensive explanations with practical examples
Interactive coding exercises to practice concepts
Knowledge quiz to test your understanding
Step-by-step guidance for beginners
Development Status
Content is being carefully crafted to provide the best learning experience
Preview
Early Preview Content
This content is still being developed and may change before publication.
13.8 — Struct aggregate initialization
In this lesson, you'll learn about aggregate initialization - a convenient way to initialize all members of a struct at the time of creation using brace notation.
The problem with member-by-member initialization
In the previous lesson, you learned to initialize struct members one by one:
#include <iostream>
struct Point
{
int x;
int y;
};
int main()
{
Point p1;
p1.x = 3; // Initialize x
p1.y = 5; // Initialize y
std::cout << "Point: (" << p1.x << ", " << p1.y << ")" << std::endl;
return 0;
}
This approach works, but it's verbose and can be error-prone. What if you forget to initialize a member? Let's see what happens:
#include <iostream>
struct Student
{
std::string name;
int age;
double gpa;
};
int main()
{
Student alice;
alice.name = "Alice Johnson";
// Forgot to initialize age and gpa!
std::cout << "Name: " << alice.name << std::endl;
std::cout << "Age: " << alice.age << std::endl; // Undefined value!
std::cout << "GPA: " << alice.gpa << std::endl; // Undefined value!
return 0;
}
The uninitialized members contain garbage values, which can lead to bugs.
Introduction to aggregate initialization
Aggregate initialization allows you to initialize all the members of a struct (or other aggregate types) at the time of creation using curly braces {}
:
#include <iostream>
struct Point
{
int x;
int y;
};
int main()
{
Point p1{3, 5}; // Initialize x = 3, y = 5
std::cout << "Point: (" << p1.x << ", " << p1.y << ")" << std::endl;
return 0;
}
Output:
Point: (3, 5)
This is much cleaner and ensures all members are initialized at once!
Basic aggregate initialization syntax
Here are the different ways you can use aggregate initialization:
#include <iostream>
#include <string>
struct Rectangle
{
double width;
double height;
std::string color;
};
int main()
{
// Method 1: Direct brace initialization
Rectangle rect1{5.0, 3.0, "red"};
// Method 2: Copy initialization with braces
Rectangle rect2 = {4.0, 6.0, "blue"};
// Method 3: Uniform initialization (preferred in modern C++)
Rectangle rect3{2.5, 1.5, "green"};
std::cout << "Rectangle 1: " << rect1.width << "x" << rect1.height
<< " (" << rect1.color << ")" << std::endl;
std::cout << "Rectangle 2: " << rect2.width << "x" << rect2.height
<< " (" << rect2.color << ")" << std::endl;
std::cout << "Rectangle 3: " << rect3.width << "x" << rect3.height
<< " (" << rect3.color << ")" << std::endl;
return 0;
}
Output:
Rectangle 1: 5x3 (red)
Rectangle 2: 4x6 (blue)
Rectangle 3: 2.5x1.5 (green)
Order matters in aggregate initialization
The values in the initializer list are assigned to struct members in the order they are declared:
#include <iostream>
#include <string>
struct Person
{
std::string name; // 1st member
int age; // 2nd member
double height; // 3rd member
};
int main()
{
// Values assigned in declaration order: name, age, height
Person alice{"Alice Johnson", 25, 5.6};
std::cout << "Name: " << alice.name << std::endl;
std::cout << "Age: " << alice.age << std::endl;
std::cout << "Height: " << alice.height << std::endl;
return 0;
}
Output:
Name: Alice Johnson
Age: 25
Height: 5.6
Partial initialization
If you don't provide values for all members, the remaining members are value-initialized (set to zero or empty for basic types):
#include <iostream>
#include <string>
struct Product
{
int id;
std::string name;
double price;
int quantity;
};
int main()
{
Product item1{1001, "Laptop"}; // Only initialize first two members
std::cout << "ID: " << item1.id << std::endl;
std::cout << "Name: " << item1.name << std::endl;
std::cout << "Price: " << item1.price << std::endl; // 0.0
std::cout << "Quantity: " << item1.quantity << std::endl; // 0
return 0;
}
Output:
ID: 1001
Name: Laptop
Price: 0
Quantity: 0
Empty initialization
You can initialize all members to their default values using empty braces:
#include <iostream>
#include <string>
struct Statistics
{
int count;
double average;
std::string category;
};
int main()
{
Statistics stats{}; // All members initialized to default values
std::cout << "Count: " << stats.count << std::endl; // 0
std::cout << "Average: " << stats.average << std::endl; // 0.0
std::cout << "Category: '" << stats.category << "'" << std::endl; // ""
return 0;
}
Output:
Count: 0
Average: 0
Category: ''
Initializing nested structs
You can use aggregate initialization with nested structs using nested braces:
#include <iostream>
#include <string>
struct Address
{
std::string street;
std::string city;
int zipCode;
};
struct Person
{
std::string name;
int age;
Address homeAddress;
};
int main()
{
// Initialize nested struct with nested braces
Person john{
"John Smith",
35,
{"123 Main St", "Springfield", 62701}
};
std::cout << "Name: " << john.name << std::endl;
std::cout << "Age: " << john.age << std::endl;
std::cout << "Address: " << john.homeAddress.street << std::endl;
std::cout << " " << john.homeAddress.city << ", "
<< john.homeAddress.zipCode << std::endl;
return 0;
}
Output:
Name: John Smith
Age: 35
Address: 123 Main St
Springfield, 62701
Aggregate initialization in function calls
You can use aggregate initialization when passing structs to functions:
#include <iostream>
struct Circle
{
double radius;
std::string color;
};
double calculateArea(const Circle& circle)
{
return 3.14159 * circle.radius * circle.radius;
}
void printCircle(const Circle& circle)
{
std::cout << "Circle: radius=" << circle.radius
<< ", color=" << circle.color
<< ", area=" << calculateArea(circle) << std::endl;
}
int main()
{
// Pass temporarily constructed Circle objects
printCircle({5.0, "red"});
printCircle({3.0, "blue"});
// You can also create and pass in one line
Circle myCircle{2.5, "green"};
printCircle(myCircle);
return 0;
}
Output:
Circle: radius=5, color=red, area=78.5397
Circle: radius=3, color=blue, area=28.2743
Circle: radius=2.5, color=green, area=19.6349
Arrays of structs with aggregate initialization
You can initialize arrays of structs using nested aggregate initialization:
#include <iostream>
#include <string>
struct Student
{
std::string name;
int age;
double gpa;
};
int main()
{
Student students[3] = {
{"Alice Johnson", 20, 3.8},
{"Bob Smith", 19, 3.2},
{"Carol Davis", 21, 3.9}
};
std::cout << "Class roster:" << std::endl;
for (int i = 0; i < 3; ++i)
{
std::cout << students[i].name << " (age " << students[i].age
<< ", GPA " << students[i].gpa << ")" << std::endl;
}
return 0;
}
Output:
Class roster:
Alice Johnson (age 20, GPA 3.8)
Bob Smith (age 19, GPA 3.2)
Carol Davis (age 21, GPA 3.9)
Designated initializers (C++20)
In C++20 and later, you can use designated initializers to explicitly specify which member you're initializing:
#include <iostream>
#include <string>
struct Employee
{
int id;
std::string name;
std::string department;
double salary;
};
int main()
{
// C++20 designated initializers
Employee emp1{
.id = 1001,
.name = "Alice Johnson",
.department = "Engineering",
.salary = 85000.0
};
// You can skip members (they'll be default-initialized)
Employee emp2{
.id = 1002,
.name = "Bob Smith",
.salary = 75000.0
// department will be empty string
};
std::cout << "Employee 1: " << emp1.name << " (" << emp1.department
<< "), ID: " << emp1.id << ", Salary: $" << emp1.salary << std::endl;
std::cout << "Employee 2: " << emp2.name << " (" << emp2.department
<< "), ID: " << emp2.id << ", Salary: $" << emp2.salary << std::endl;
return 0;
}
Output (C++20):
Employee 1: Alice Johnson (Engineering), ID: 1001, Salary: $85000
Employee 2: Bob Smith (), ID: 1002, Salary: $75000
Common mistakes and pitfalls
1. Too many initializers
struct Point { int x, y; };
// ERROR: too many initializers
// Point p{1, 2, 3}; // Point only has 2 members!
2. Wrong order of values
struct Person
{
std::string name;
int age;
};
// Be careful - age comes after name!
Person alice{"25", 25}; // Wrong! Will try to assign "25" to name and 25 to age
// Should be: Person alice{"Alice", 25};
3. Mixing initialization styles
struct Rectangle
{
double width;
double height;
};
int main()
{
Rectangle rect{5.0, 3.0}; // Good: aggregate initialization
// Don't mix with member assignment
rect.width = 10.0; // This changes the already-initialized value
return 0;
}
Best practices for aggregate initialization
1. Prefer aggregate initialization for simple structs
// Good: clear and concise
Point p{3, 5};
// Less preferred: more verbose
Point p;
p.x = 3;
p.y = 5;
2. Use meaningful variable names that match the member order
struct Rectangle { double width, height; };
// Good: parameter names match member order
Rectangle createRect(double w, double h)
{
return {w, h}; // Clear what w and h represent
}
3. Consider using designated initializers for clarity (C++20+)
// When member purpose isn't obvious from order
Employee emp{
.id = 1001,
.name = "Alice Johnson",
.salary = 85000.0
};
4. Initialize all members when possible
// Good: all members explicitly initialized
Student alice{"Alice Johnson", 20, 3.8};
// Less ideal: some members default-initialized
Student bob{"Bob Smith"}; // age and gpa are 0
Key concepts to remember
-
Aggregate initialization uses curly braces to initialize all struct members at once.
-
Values are assigned in the order members are declared in the struct.
-
Unspecified members are value-initialized (usually to zero or empty).
-
Empty braces initialize all members to default values.
-
Nested structs use nested braces for initialization.
-
Designated initializers (C++20+) allow explicit member naming.
Summary
Aggregate initialization provides a clean, safe way to initialize struct members using brace notation. It ensures all members are initialized at creation time, reduces verbosity, and helps prevent bugs from uninitialized data. The values are assigned in the order members are declared, and any unspecified members get default values. This initialization method works with nested structs, function parameters, and arrays, making it a versatile tool for working with structured data.
Quiz
- What is aggregate initialization and how does it differ from member-by-member initialization?
- In what order are values assigned during aggregate initialization?
- What happens to struct members that aren't specified in the initializer list?
- How do you initialize nested structs using aggregate initialization?
- What are designated initializers and when might you use them?
Practice exercises
Try these exercises with aggregate initialization:
- Create a
Book
struct and initialize several books using different aggregate initialization methods. - Create a
Color
struct with RGB values and initialize an array of colors representing a rainbow. - Create nested structs for a
Car
containing anEngine
struct, and initialize a car with all details. - Create a function that returns a struct initialized with aggregate initialization based on parameters.
Explore More Courses
Discover other available courses while this lesson is being prepared.
Browse CoursesLesson Discussion
Share your thoughts and questions