The member initializer list for a class constructor allows members to be initialized to specified values as well as base class constructors to be called with specific arguments. However, the order in which initialization occurs is fixed and does not depend on the order written in the member initializer list. According to the C++ 2003, Section 12.6.2 "Initializing bases and members", paragraph 5, says:Standard, [class.base.init], paragraph 11 [ISO/IEC 14882-2014]:
In a non-delegating constructor, initialization proceeds Initialization shall proceed in the following order:
â” — First, and only for the constructor of the most derived class as described below, virtual base classes shall be are initialized in the in the order they appear on a depth-first left-to-right traversal of the directed acyclic graph of base classes, where âleft where “left-to-rightâ right” is the order of appearance of the base class names classes in the derived class base-specifier-list.
â” — Then, direct base classes shall be are initialized in declaration order as they appear in the base-specifier-list list (regardless of the order of the mem-initializers).
â” — Then, nonstatic non-static data members shall be are initialized in the order they were declared in the class definition definition (again regardless of the order of the mem-initializers).
â” — Finally, the body compound-statement of the constructor body is executed.
[Note: The declaration order is mandated to ensure that base and member subobjects are destroyed in the reverse order of initialization. —end note]
Consequently, the order in which constructor member initializers appear is actually irrelevent, as the in the member initializer list is irrelevant. The order in which they are executed members are initialized, including base class initialization, is determined by external items, such as the declaration order of the class member variables, or the base class fields. Reordering the initializers has no effect on the code execution, but can confuse programmers and lead to undefined behavior.
...
specifier list. Writing member initializers in an order other than the canonical one can result in undefined behavior, such as reading uninitialized memory.
Always write member initializers in a constructor in the canonical order: first, direct base classes in the order they appear in the base-specifier-list for the class, then nonstatic data members in the order they are declared in the class definition.
Noncompliant Code Example
In this noncompliant code example, the member initializer list for C::C()
attempts to initialize SomeVal
first, and then initialize DependsOnSomeVal
to a value dependent on SomeVal
. However, since the declaration order of the member variables does not match the member initializer order, attempting to read the value of SomeVal
results in an unspecified value being stored into DependsOnSomeVal.
Code Block | ||||
---|---|---|---|---|
| ||||
class C { int aDependsOnSomeVal; int bSomeVal; public: C(int val) : bSomeVal(3val), aDependsOnSomeVal(bSomeVal + 1) {} }; |
In class c
's default constructor a
is initialized before b
because a
is declared before b
in the class body. Consequently a
's initialization depends on the unitialized value of b
, and so a
will likely hold garbage.
Implementation Details
MSVC 2008 compiles this code without warning. It sets c.b
to 3, and c.a
to -858993459.
G++ 4.3.3 issues a warning regarding the misordered initializers. It sets c.b
to 3 and c.a
to 32515.
Non-Compliant Code Example
Compliant Solution
This compliant solution changes the declaration order of the class member variables so that the dependency can be ordered properly in the constructor's member initializer list:
Code Block | ||||
---|---|---|---|---|
| ||||
class C {
int SomeVal;
int DependsOnSomeVal;
public:
C(int val) : SomeVal(val), DependsOnSomeVal(SomeVal + 1) {}
};
|
Note that it is reasonable for initializers to depend on previously initialized values.
Noncompliant Code Example
In this noncompliant code example, the derived class, D
, attempts to initialize the base class, B1
, with a value obtained from the base class, B2
. However, because B1
is initialized before B2
due to the declaration order in the base class specifier list, the results are undefined.This code reorders the initializers correctly:
Code Block | ||||
---|---|---|---|---|
| ||||
class CB1 { int Val; public: B1(int a; V) : Val(V) {} }; class B2 { int bOtherVal; public: CB2(int V) : aOtherVal(b+1), b(3) {V) {} int getOtherVal() const { return OtherVal; } }; |
This code is still noncompliant, but now the error is obvious, a
clearly depends on b
despite being initialized first.
Compliant Solution
class D : B1, B2 {
D(int A) : B2(A), B1(getOtherVal()) {}
}; |
Compliant Solution
This compliant solution initializes both base classes using the same value from the constructor's parameter list, instead of relying on the initialization order of the base classes:This code resolves the dependency.
Code Block | ||||
---|---|---|---|---|
| ||||
class CB1 { int Val; public: B1(int a; int b; V) : Val(V) {} }; class B2 { int OtherVal; public: B2(int V) C(: OtherVal(V) {} }; class D : B1, B2 { D(int A) : aB2(4A), bB1(a-1A) {} }; |
Note that it is perfectly reasonable for initializers to depend on previously initialized values.
Risk Assessment
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
OOP37-CPP | mediumMedium | probableUnlikely | mediumMedium | P8P4 | L2L3 |
Automated Detection
Tool | Version | Checker | Description | ||||||
| 4053,4056,4058 |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
Related Guidelines
Bibliography
[ISO/IEC 14882-2014] | 12.6.2, "Initializing Bases and Members" |
[Lockheed Martin 05] |
...
Rule 75, "Members of the initialization list shall be listed in the order in which they are declared in the class" |
.
[ISO/IEC 14882-2003] Section 12.6.2 "Initializing bases and members"
OOP36-CPP. Do not assume that copy constructor invocations will not be elided 013. Object Oriented Programming (OOP) 014. Concurrency (CON)