Ready to practice?
Sign up to access interactive coding exercises and track your progress.
Efficient Member Initialization
Initialize members directly in the member initializer list for efficiency and correctness.
Constructor Member Initializer Lists
In the previous lesson, we initialized members by assigning values in the constructor body. There's a better way: member initializer lists.
Assignment vs. initialization
Constructor body uses assignment:
class Coordinates
{
public:
int x{};
int y{};
Coordinates(int xPos, int yPos)
{
x = xPos; // Assignment
y = yPos; // Assignment
}
};
What actually happens:
- Members are default-initialized (x=0, y=0)
- Then assigned new values
This is wasteful—why initialize twice?
Member initializer lists
A member initializer list directly initializes members before the constructor body runs:
class Coordinates
{
public:
int x{};
int y{};
Coordinates(int xPos, int yPos)
: x{ xPos }, y{ yPos } // Member initializer list
{
// Constructor body (can be empty)
}
};
Members are initialized once, directly to their final values. More efficient!
Syntax
The member initializer list appears after the constructor parameter list, starting with a colon:
ClassName(parameters)
: member1{ value1 }, member2{ value2 }, member3{ value3 }
{
// Constructor body
}
When member initializer lists are required
Const members must use initializer lists (can't be assigned after creation):
class Setting
{
public:
const int maxValue{};
Setting(int max)
: maxValue{ max } // Must use initializer list
{
// maxValue = max; // Error: can't assign to const
}
};
Reference members must use initializer lists:
class Reference
{
public:
int& target;
Reference(int& value)
: target{ value } // Must use initializer list
{
// target = value; // Error: references can't be reseated
}
};
Members without default constructors:
class FullName
{
public:
std::string first{};
std::string last{};
FullName(std::string f, std::string l)
: first{ f }, last{ l } // Efficient: direct initialization
{
}
};
Initialization order
Members are initialized in the order they're declared in the class, NOT the order in the initializer list:
class Order
{
public:
int first{};
int second{};
Order(int value)
: second{ value }, first{ second * 2 } // Dangerous!
{
}
};
This initializes first first (because it's declared first), using an uninitialized second. Bug!
List members in initializer list in the same order they're declared in the class to avoid initialization order bugs.
Combining initializer list and constructor body
You can use both:
class Writer
{
public:
std::string path{};
std::ofstream output{};
Writer(std::string filePath)
: path{ filePath } // Initialize member
{
output.open(path); // Perform action in body
}
};
Use the initializer list for member initialization. Use the constructor body for logic, validation, or operations.
Multiple members example
class Area
{
private:
double width{};
double height{};
double size{};
public:
Area(double w, double h)
: width{ w }, height{ h }, size{ w * h }
{
}
double getSize() const { return size; }
};
Const correctness
Member initializer lists work well with const members:
class Radius
{
private:
const double value{};
const double pi{ 3.14159 };
public:
Radius(double r)
: value{ r }
{
}
double circumference() const
{
return 2 * pi * value;
}
};
Once constructed, value and pi cannot change.
Efficiency matters
For class types, member initializer lists avoid unnecessary operations:
class Warrior
{
public:
std::string title{};
// Less efficient
Warrior(std::string t)
{
title = t; // Default construct, then assign
}
// More efficient
Warrior(std::string t)
: title{ t } // Direct construction
{
}
};
The second version constructs title once, directly with the value. The first constructs it as empty, then assigns.
Prefer member initializer lists over assignment in the constructor body. List members in declaration order to avoid subtle bugs. Use initializer lists for all member initialization, especially const members, reference members, and members without default constructors. Use the constructor body for validation, calculations, setting up resources, and error handling.
class Vault
{
private:
const int id{};
int contents{};
public:
Vault(int vaultId, int initialContents)
: id{ vaultId }, contents{} // Initialize in list
{
if (initialContents >= 0) // Validate in body
contents = initialContents;
}
};
Summary
Assignment vs. initialization: Constructor bodies use assignment, which means members are first default-initialized and then assigned new values. This is wasteful compared to direct initialization.
Member initializer lists: These directly initialize members before the constructor body runs, eliminating the default initialization step and making construction more efficient.
Required for certain members: Const members, reference members, and members without default constructors must use initializer lists since they cannot be assigned after creation.
Initialization order: Members are initialized in the order they're declared in the class definition, not the order they appear in the initializer list. Always list members in declaration order to avoid bugs.
Combining both approaches: Use initializer lists for member initialization and the constructor body for validation, calculations, or other logic that needs to happen after members are initialized.
Efficiency matters: For class types, initializer lists avoid creating temporary default objects and then assigning to them, instead constructing members directly with their final values.
Member initializer lists are the preferred way to initialize class members. They're more efficient than assignment, required for certain member types, and create clearer, more maintainable code by separating initialization from logic.
Efficient Member Initialization - Quiz
Test your understanding of the lesson.
Practice Exercises
Member Initializer Lists
Use member initializer lists to properly initialize class members in constructors.
Lesson Discussion
Share your thoughts and questions
No comments yet. Be the first to share your thoughts!