Main Content

MISRA C++:2023 Rule 15.1.5

A class shall only define an initializer-list constructor when it is the only constructor

Since R2024b

Description

Rule Definition

A class shall only define an initializer-list constructor when it is the only constructor.

Rationale

If a class contains a constructor that takes a parameter of type std::initializer_list and another constructor with parameters, braced initializations such as:

classType obj {0,1}
Can lead to confusion about which of the two constructors is invoked. Compilers prefer the constructor with the std::initializer_list parameter, but developers might expect otherwise.

Polyspace Implementation

The checker flags class definitions that contain a constructor whose first parameter is of type std::initializer_list and also contains another constructor (excluding the special member function constructors). The rule violation is followed by events that point to the location of the other constructors that might lead to confusion with the std::initializer_list constructor.

A class definition with an std::initializer_list-parameter constructor that does not violate this rule has only the default, copy and move constructors (and copy and move assignment operators). If you cannot avoid a second constructor with parameters, you can justify this rule violation. In that case, for initializing with a list, use a syntax such as:

classType obj ({0,1})
so that it is clear that the std::initializer_list-parameter constructor is invoked. For initializing with the other constructors, use a syntax such as:
classType obj (0,1)
Both invocations are exceptions to Rule A8-5-2, which generally flags initializations with (), but allows such initializations for classes with a mix of std::initializer_list-parameter constructor and other constructors.

Troubleshooting

If you expect a rule violation but Polyspace® does not report it, see Diagnose Why Coding Standard Violations Do Not Appear as Expected.

Examples

expand all

#include <cstdint>
#include <initializer_list>
#include <vector>

class entrySizes {                  //Noncompliant
    public:
       entrySizes()=default;
       entrySizes(std::size_t aCurrentSize, std::size_t aLastSize): 
              currentSize{aCurrentSize}, lastSize{aLastSize} {}
       entrySizes(std::initializer_list<std::size_t> sampleEntry): 
              currentSize{sampleEntry.size()}, lastSize{sampleEntry.size()} {}
    private:
       std::size_t currentSize;
       std::size_t lastSize;
};

class recordSizes {                 //Compliant
    public:
       recordSizes()=default;
       recordSizes(std::initializer_list<std::size_t> sampleRecord): 
              currentSize{sampleRecord.size()}, lastSize{sampleRecord.size()} {}
    private:
       std::size_t currentSize;
       std::size_t lastSize;
};


void createEntry() {
    entrySizes defaultEntrySize{};
    entrySizes stdEntrySize{0,1}; 
       //Calls entrySizes(std::initializer_list<std::size_t> ), 
       //but developer might expect otherwise
    entrySizes expectedEntrySize({0,1}); 
       //Calls entrySizes(std::initializer_list<std::size_t> ), 
       //but developer might expect otherwise
    entrySizes typicalEntrySize(1,1); 
        //Calls entrySizes(std::size_t, std::size_t)
}

void createRecord() {
    recordSizes defaultRecordSize{};
    recordSizes stdRecordSize{0,1}; 
       //Calls recordSizes(std::initializer_list<std::size_t> )
}

In this example, the class entrySizes contains two user-defined constructors, one with an std::initialize_list parameter and a second one with two size_t parameters. The presence of two constructors can lead to developer confusion as shown in the createEntry function. In case you want to retain the current class definition and justify the rule violation, the createEntry function also shows a cleaner way to invoke the std::initialize_list-parameter constructor.

The class recordSizes does not violate the rule since it does not contain another constructor other than the default constructor and the constructor with the std::initialize_list parameter.

Check Information

Group: Special member functions
Category: Required

Version History

Introduced in R2024b