This rule is part of MISRA C++:2023.
Usage of this content is governed by Sonar’s terms and conditions. Redistribution is
prohibited.
Rule 15.1.4 - All direct, non-static data members of a class should be initialized before the class object is accessible
Category: Advisory
Analysis: Decidable,Single Translation Unit
Amplification
A class object is considered accessible:
- At the top of the compound-statement that forms the constructor body;
- For an aggregate, as soon as the object is created.
A data member is initialized at the top of a constructor body if:
- The constructor is a delegating constructor; or
- The data member has a default member initializer; or
- The data member appears in the constructor’s member initialization list; or
- The data member’s type has a constructor.
A data member of an aggregate is initialized if:
- The data member has a default member initializer; or
- The object’s declaration [1] has an initializer; or
- The data member’s type has a constructor.
For the purposes of this rule, an implicitly or explicitly defaulted constructor is treated as if its synthesized body was user-written.
Rationale
A constructor should completely initialize its object. Explicit initialization reduces the risk of an invalid state existing after successful
construction. Note — the initialization of base classes is covered by M23_172: MISRA C++ 2023 Rule 15.1.2.
Each non-static data member should be initialized, preferably using a default member initializer, or else within a constructor member
initialization list.
Assigning to the variable in the constructor body is not sufficient, as requiring members to be initialized at the top of the constructor allows
compliance checking for this rule to be made decidable.
Note: compliance with this rule means that constructors will often have an empty body.
For an aggregate, non-static data members can be initialized either by using default member initialization or aggregate
initialization when declaring an object.
Example
class PersonClass
{
public:
PersonClass( string const & name, int32_t age ) :
name { name }, age { age } // Compliant
{}
explicit PersonClass( int32_t age ) :
age { age } // Compliant - name is default constructed,
{} // and income initialized to 1000
explicit PersonClass( string const & name ) :
name { name } // Non-compliant - age not initialized
{
age = 18;
}
PersonClass() = default; // Non-compliant - age not initialized
private:
string name;
int32_t age;
int32_t income = 1000;
};
class PersonAggregate
{
public:
string name;
int32_t age;
int32_t income { 1000 };
};
void f()
{
PersonAggregate p1; // Non-compliant - age not initialized, even though
// name and income are initialized
PersonAggregate p2 {}; // Compliant - name is default constructed, and age is
} // initialized to 0, income to 1000
class Building // Non-compliant - height not initialized in the
{ // implicit default constructor
private:
string name;
public:
int32_t height;
}
class Base
{
int32_t a;
public:
explicit Base( int32_t a ) : // Compliant
a { a } { }
};
class Derived : public Base
{
int32_t b;
public:
Derived() : // Compliant
Base { 0 }, b {} {}
using Base::Base; // Non-compliant - b not initialized by the
}; // synthesized constructor
Glossary
[1] Declaration
A declaration introduces the name of an entity into a translation unit (see [basic.def]/1).
An entity may be declared several times. The first declaration of an entity in a translation unit is
called an introduction [2]. All subsequent declarations are called redeclarations [3].
A definition [4] is a declaration, as described in [basic.def]/2.
[2] Introduction
See declaration [1].
[3] Redeclaration
See declaration [1].
[4] Definition
See declaration [1].
Copyright The MISRA Consortium Limited © 2023