Unofficial Autosar C++ Guidelines Reference

This project has the aim to provide an easier access to the document [1]. Instead of a PDF file, the contents are transferred to a searchable online book using mdbook.

Due to the automatic generation of this book, please expect wrongly formatted content, content in the wrong section or even missing content.

The source for this book is available at [2].

Content Generation

To generate the content of this page, a lot of regex logic is used to extract the relevant information out of the PDF document [1].

  1. Download the document [1] from the official source
  2. Convert the document to a txt format using e.g. Cloudconvert
  3. Place the txt file in the script dicrectory and call ./convert.sh [name].txt

convert.sh uses the following commands to extract and format the content from the txt source:

  • sed
  • csplit
  • prettier

At the end, Markdown files are generated and copied to the src folder to be published by mdbook.

ToDo

  • Format C++ code blocks automatically
  • Improve regex to close code blocks

License

This project utilizes the work [1] without any modification for informational purposes only in accordance with its disclaimer.

The parts of this repository that do not originate from [1] are licensed with the GPL 3.0 license. Also see LICENSE.

[1] Guidelines for the use of the C++14 language in critical and safety-related systems AUTOSAR AP Release 19-03

[2] GitHub

Rule M0-1-1 (required, implementation, automated)

A project shall not contain unreachable code.

See MISRA C++ 2008 [7]

Rule M0-1-2 (required, implementation, automated)

A project shall not contain infeasible paths.

See MISRA C++ 2008 [7]

Note: A path can also be infeasible because of a call to constexpr function which returned value, known statically, will never fulfill the condition of a condition statement.

Rule M0-1-3 (required, implementation, automated)

A project shall not contain unused variables.

See MISRA C++ 2008 [7]

Rule M0-1-4 (required, implementation, automated)

A project shall not contain non-volatile POD variables having only one use.

See MISRA C++ 2008 [7]

Rule A0-1-1 (required, implementation, automated)

A project shall not contain instances of non-volatile variables being given values that are not subsequently used.

Rationale

Known as a DU dataflow anomaly, this is a process whereby there is a data flow in which a variable is given a value that is not subsequently used. At best this is inefficient, but may indicate a genuine problem. Often the presence of these constructs is due to the wrong choice of statement aggregates such as loops.

See: DU-Anomaly.

Exception

Loop control variables (see Section 6.6.5) are exempt from this rule.

Example

//% $Id: A0-1-1.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <array>
#include <cstdint>
std::uint8_t Fn1(std::uint8_t param) noexcept
{
    std::int32_t x{
        0}; // Non-compliant - DU data flow anomaly; Variable defined,
            // but not used
    if (param > 0)
    {
        return 1;
    }
    else
    {
        return 0;
    }
}
std::int32_t Fn2() noexcept
{
    std::int8_t x{10U}; // Compliant - variable defined and will be used
    std::int8_t y{20U}; // Compliant - variable defined and will be used
    std::int16_t result = x + y; // x and y variables used

    x = 0; // Non-compliant - DU data flow anomaly; Variable defined, but x is
           // not subsequently used and goes out of scope
    y = 0; // Non-compliant - DU data flow anomaly; Variable defined, but y is
           // not subsequently used and goes out of scope
    return result;
}
std::int32_t Fn3(std::int32_t param) noexcept
{
    std::int32_t x{param +
        1}; // Compliant - variable defined, and will be used in
            // one of the branches
            // However, scope of x variable could be reduced
    if (param > 20)
    {
        return x;
    }
    return 0;
}
std::int32_t Fn4(std::int32_t param) noexcept

{
    std::int32_t x{param +

        1}; // Compliant - variable defined, and will be used in
            // some of the branches

    if (param > 20)
    {
        return x + 1;
    }
    else if (param > 10)
    {
        return x;
    }
    else
    {
        return 0;
    }
}
void Fn5() noexcept
{
    std::array<std::int32_t, 100> arr{};
    arr.fill(1);

    constexpr std::uint8_t limit{100U};
    std::int8_t x{0};
    for (std::uint8_t i{0U}; i < limit; ++i) // Compliant by exception - on the
                                             // final loop, value of i defined will
                                             // not be used
    {
        arr[i] = arr[x];
        ++x; // Non-compliant - DU data flow anomaly on the final loop, value
             // defined and not used
    }

}

See also

MISRAC++2008: 0-1-6 A project shall not contain instances of non-volatile variables being given values that are never subsequently used.

Rule A0-1-2 (required, implementation, automated)

The value returned by a function having a non-void return type that is not an overloaded operator shall be used.

Rationale

A called function may provide essential information about its process status and result through return statement. Calling a function without using the return value should be a warning that incorrect assumptions about the process were made. Overloaded operators are excluded, as they should behave in the same way as builtin operators.

Exception

The return value of a function call may be discarded by use of a static_cast cast, so intentions of a programmer are explicitly stated.

Example

// $Id: A0-1-2.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <algorithm>
#include <cstdint>
#include <vector>
std::uint8_t Fn1() noexcept
{
    return 0U;
}
void Fn2() noexcept
{
    std::uint8_t x = Fn1(); // Compliant
    Fn1(); // Non-compliant
    static_cast<void>(Fn1()); // Compliant by exception
}
void Fn3()
{
    std::vector<std::int8_t> v{0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5};
    std::unique(v.begin(), v.end()); // Non-compliant
    v.erase(std::unique(v.begin(), v.end()), v.end()); // Compliant
}

See also

MISRA C++ 2008 [7]: Rule 0-1-7 The value returned by a function having a non-void return type that is not an overloaded operator shall always be used.

HIC++ v4.0 [9]: 17.5.1 Do not ignore the result of std::remove, std::remove_if or std::unique.

Rule M0-1-8 (required, implementation, automated)

All functions with void return type shall have external side effect(s). See MISRA C++ 2008 [7]

Rule M0-1-9 (required, implementation, automated)

There shall be no dead code. See MISRA C++ 2008 [7]


## See also
JSF December 2005 [8]: AV Rule 181: Redundant explicit casts will not be used.

Rule M0-1-10 (advisory, implementation, automated)

Every defined function should be called at least once.

See MISRA C++ 2008 [7] Note: This rule enforces developers to statically and explicitly use every function in the source code. A function does not necessarily need to be called at run-time. Rule M0-1-1 detects all unreachable code occurrences.

Rule A0-1-3 (required, implementation, automated)

Every function defined in an anonymous namespace, or static function with internal linkage, or private member function shall be used.

Rationale

Functions which are not callable from outside the compilation unit in which they are defined, or from outside the class implementation to which they pertain, and which are not used may be symptomatic of serious problems, such as poor software design or missing paths in flow control. This rule enforces developers to statically and explicitly use every such function in the source code. A function does not necessarily need to be called at run-time. Rule M0-1-1 detects all unreachable code occurrences. Note that this rule applies equally to static and non-static private member functions.

Example

//% $Id: A0-1-3.cpp 291350 2017-10-17 14:31:34Z jan.babst $
#include <cstdint>
static void F1() // Compliant
{
}

namespace
{
void F2() // Non-compliant, defined function never used
{
}
}

class C
{
public:
C() : x(0) {}
void M1(std::int32_t i) // Compliant, member function is used
{
x = i;
}

void M2(std::int32_t i,
std::int32_t j) // Compliant, never used but declared
// as public
{
x = (i > j) ? i : j;
}

protected:
void M1ProtectedImpl(std::int32_t j) // Compliant, never used but declared
// as protected
{
x = j;
}

private:
std::int32_t x;
void M1PrivateImpl(
std::int32_t j) // Non-compliant, private member function never used
{
x = j;
}

};

int main(int, char**)

{
F1();
C c;
c.M1(1);
return 0;

}

See also

MISRA C++ 2008 [7]: Rule 0-1-10 Every defined function shall be called at least once. HIC++ v4.0 [9]: 1.2.2 Ensure that no expression or sub-expression is redundant.

Rule A0-1-4 (required, implementation, automated)

There shall be no unused named parameters in non-virtual functions.

Rationale

Unused named parameters are often a result of a design changes and can lead to mismatched parameter lists. Note: This rule does not apply to unnamed parameters, as they are widely used in SFINAE and concept compliance.

Example

//% $Id: A0-1-4.cpp 305588 2018-01-29 11:07:35Z michal.szczepankiewicz $

#include <type_traits>
#include <string>

//Logger.hpp
class Logger
{
public:
struct console_t {};
struct file_t {};

constexpr static console_t console = console_t();
constexpr static file_t file = file_t();

void init(console_t);
void init(file_t, const std::string& prefix);

};

//Logger.cpp
void Logger::init(console_t)
{
//initialization for a console logger
}
void Logger::init(file_t, const std::string& prefix)
{
//initialization for a file logger for a given prefix path
}

//Message.h
struct MessagePolicy {};
struct WriteMessagePolicy final : public MessagePolicy { };

template <typename T> struct is_mutable : std::false_type {};
template <> struct is_mutable<WriteMessagePolicy> : std::true_type {};

template <typename T, typename Policy = MessagePolicy>
class Message
{
public:
static_assert(std::is_base_of<MessagePolicy, Policy>::value == true, "Given parameter is not
derived from MessagePolicy");
using value_type = T;

template<typename U = void>
void set(T&& u, typename std::enable_if<is_mutable<Policy>::value, U>::type*

= 0)
{
v = u;

}

private:
value_type v;
};

int main(int, char**)

{
Logger log;
log.init(Logger::console);
log.init(Logger::file, std::string("/tmp/"));

Message<uint8_t> read;
Message<uint8_t, WriteMessagePolicy> write;

//read.set(uint8_t(12)); Compilation error
write.set(uint8_t(12));

return 0;

}

See also

C++ Core Guidelines [11]: F.9: Unused parameters should be unnamed

Rule A0-1-5 (required, implementation, automated)

There shall be no unused named parameters in the set of parameters for a virtual function and all the functions that override it.

Rationale

Unused named parameters are often a result of a design changes and can lead to mismatched parameter lists. Note: This rule does not apply to unnamed parameters, as overridden methods for some subclasses may need additional parameters.

Example

//% $Id: A0-1-5.cpp 305588 2018-01-29 11:07:35Z michal.szczepankiewicz $

#include <cstdint>
#include <vector>

//Compressor.h
class Compressor
{
public:
using raw_memory_type = std::vector<uint8_t>;

raw_memory_type Compress(const raw_memory_type& in, uint8_t ratio);

private:

virtual raw_memory_type __Compress(const raw_memory_type& in, uint8_t ratio)
= 0;

};

//Compressor.cpp
Compressor::raw_memory_type Compressor::Compress(const raw_memory_type& in, uint8_t
ratio)
{
return __Compress(in, ratio);
}

//JPEGCompressor.h
class JPEGCompressor : public Compressor
{
private:
raw_memory_type __Compress(const raw_memory_type& in, uint8_t ratio) override
;
};

//JPEGCompressor.cpp
JPEGCompressor::raw_memory_type JPEGCompressor::__Compress(const raw_memory_type& in,
uint8_t ratio)
{
raw_memory_type ret;
//jpeg compression, ratio used
return ret;
}

//HuffmanCompressor.h
class HuffmanCompressor : public Compressor
{
private:
raw_memory_type __Compress(const raw_memory_type& in, uint8_t) override;
};

//JPEGCompressor.cpp
HuffmanCompressor::raw_memory_type HuffmanCompressor::__Compress(const
raw_memory_type& in, uint8_t)
{
raw_memory_type ret;
//Huffman compression, no ratio parameter available in the algorithm
return ret;
}

See also

C++ Core Guidelines [11]: F.9: Unused parameters should be unnamed

Rule A0-1-6 (advisory, implementation, automated)

There should be no unused type declarations.

Rationale

Unused type declarations make code unnecessary more complex and complicate review process. Unused types can be redundant or be unused by mistake. Note: Libraries development require introduction new types not used internally.

Example

// $Id: A0-1-6.cpp$
#include <cstdint>

std::uint32_t Fn() noexcept
{
using LocalUIntPtr = std::uint32_t*;

return 0U;

}

See also

MISRA C++ 2008 [7]: Rule 0-1-5 reclassified from required to advisory.

Rule M0-2-1 (required, implementation, automated)

An object shall not be assigned to an overlapping object. See MISRA C++ 2008 [7]

Rule M0-3-1 (required, implementation / verification, non-automated)Minimization of run-time failures shall be ensured by the use of at least one of: (a) static analysis tools/techniques; (b) dynamic analysis tools/techniques; (c) explicit coding of checks to handle run-time faults. See MISRA C++ 2008 [7]

Rule M0-3-2 (required, implementation, non-automated)

If a function generates error information, then that error information shall be tested. See MISRA C++ 2008 [7] Note: This rule does not cover exceptions due to different behavior. Exception handling is described in chapter 6.15.

Rule M0-4-1 (required, implementation, non-automated)

Use of scaled-integer or fixed-point arithmetic shall be documented. See MISRA C++ 2008 [7]

Rule A0-4-1 (required, infrastructure / toolchain, non-automated)

Floating-point implementation shall comply with IEEE 754 standard.

Rationale

Floating-point arithmetic has a range of problems associated with it. Some of these can be overcome by using an implementation that conforms to IEEE 754 (IEEE Standard for Floating-Point Arithmetic). Note that the rule implies that toolchain, hardware, C++ Standard Library and C++ built-in types (i.e. float, double) will provide full compliance to IEEE 754 standard in order to use floating-points in the project. Also, see: A0-4-2.

Example

//% $Id: A0-4-1.cpp 271389 2017-03-21 14:41:05Z piotr.tanski $
#include <limits>

static_assert(std::numeric_limits<float>::is_iec559,
"Type float does not comply with IEEE 754 single precision format");

static_assert( std::numeric_limits<float>::digits == 24,
"Type float does not comply with IEEE 754 single precision format");

static_assert( std::numeric_limits<double>::is_iec559,
"type double does not comply with IEEE 754 double precision format");

static_assert( std::numeric_limits<double>::digits == 53,
"Type double does not comply with IEEE 754 double precision format");

See also

MISRA C++ 2008 [7]: Rule 0-4-3 Floating-point implementations shall comply with a defined floating-point standard. JSF December 2005 [8]: AV Rule 146 Floating point implementations shall comply with a defined floating point standard.

Rule M0-4-2 (required, implementation, non-automated)

Use of floating-point arithmetic shall be documented.

See MISRA C++ 2008 [7]

Rule A0-4-2 (required, implementation, automated)

Type long double shall not be used.

Rationale

The width of long double type, and therefore width of the significand, is implementation-defined. The width of long double type can be either: 64 bits, as the C++14 Language Standard allows long double to provide at least as much precision as type double does, or 80 bits, as the IEEE 754 standard allows extended precision formats (see: Extended-Precision-Format), or

Example

//% $Id: A0-4-2.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
void Fn() noexcept
{
float f1{0.1F};
// Compliant
double f2{0.1};
// Compliant
long double f3{0.1L}; // Non-compliant
}

See also

none

Rule A0-4-3 (required, toolchain, automated)

The implementations in the chosen compiler shall strictly comply with the C++14 Language Standard.

Rationale

It is important to determine whether implementations provided by the chosen compiler strictly follow the ISO/IEC 14882:2014 C++ Language Standard.

Example

Since the ISO/IEC 14882:2014 C++ Language Standard, the integer division and modulo operator results are no longer implementation-defined. The sentence “if both operands are nonnegative then the remainder is nonnegative; if not, the sign of the remainder is implementation-defined” from ISO/IEC 14882:2003 is no longer present in the standard since ISO/IEC 14882:2011. Note that this rule also covers the modulo operator as it is defined in terms of integer division. Deducing the type of an auto variable initialized using auto x{} is implemented differently depending on the language standard. In C++11 and C++14, x will be a std::initializer_list, whereas in C++17, x will be a type deduced from the specified . Furthermore, some compilers may already implement the C++17 behavior even when operated in C++14 mode. Note: Rule A8-5-3 forbids initializing an auto variable with the curly braces ({}) syntax. Other features provided by the chosen compiler also should follow the ISO/IEC


## See also
MISRA C++ 2008 [7]: Rule 1-0-3 The implementation of integer division in the
chosen compiler shall be determined and documented.
C++ Core Guidelines [11]: F.46: int is the return type for main().

Rule A0-4-4 (required, implementation, partially automated)

Range, domain and pole errors shall be checked when using math functions.

Rationale

The C Standard defines the following types of error related to math functions specifically: domain error – input arguments are outside a domain of a mathematical function definition pole error – for finite input arguments a function gives an exact infinite result

range error – a result of a mathematical function cannot be represented by the return type limitations Domain and pole errors require that bounds are checked for input parameters before calling a mathematical function. Range errors in most cases cannot be prevented, as their occurrence mostly depend on the implementation of floating-point numbers (see A0-4-1). Checking for range errors for multi-threaded applications require that floating-point exception state is in a per-thread basis.

Example

//% $Id: A0-4-4.cpp 305588 2018-01-29 11:07:35Z michal.szczepankiewicz $

#include <cmath>
#include <cfenv>

float Foo(float val)
{
//non-compliant, domain error for negative values
return std::sqrt(val);
}

float Bar(float val)
{
//non-compliant
//domain error for val < 0
//pole error for val==0
return std::log(val);
}

// \return true, if a range error occurred
bool DetectRangeErr()
{
return ((math_errhandling & MATH_ERREXCEPT) &&
(fetestexcept(FE_INEXACT | FE_OVERFLOW | FE_UNDERFLOW) != 0));
}

See also

SEI CERT C++ Coding Standard [10]: FLP32-C: Prevent or detect domain and range errors in math functions

Rule A1-1-1 (required, implementation, automated)

All code shall conform to ISO/IEC 14882:2014 - Programming Language C++ and shall not use deprecated features.

Rationale

The current version of the C++ language is as defined by the ISO International Standard ISO/IEC 14822:2014(E) "Information technology - Programming languages

  • C++". The C++14 is the improved version of the C++11. It is also “the state of the art” of C++ development that is required by ISO 26262 standard [6]. Any reference in this document to “C++ Language Standard” refers to the ISO/IEC Note that all of the deprecated features of C++ Language Standard are defined in ISO/IEC 14882:2014 - Programming Language C++ Annexes C “Compatibility” and D “Compatibility features”.

Example

//% $Id: A1-1-1.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <cstdint>
#include <stdexcept>
void F(std::int32_t i)
{
std::int32_t* a = nullptr;

// __try // Non-compliant - __try is a part of Visual Studio extension
try // Compliant - try keyword is a part of C++ Language Standard
{
a = new std::int32_t[i];
// ...
}

// __finally // Non-compliant - __finally is a part of Visual Studio
// extension
catch (
std::exception&) // Compliant - C++ Language Standard does not define
// finally block, only try and catch blocks
{
delete[] a;
a = nullptr;
}

}

See also

MISRA C++ 2008 [7]: 1-0-1 All code shall conform to ISO/IEC 14882:2003 “The C++ Standard Incorporating Technical Corrigendum 1”

JSF December 2005 [8]: 4.4.1 All code shall conform to ISO/IEC HIC++ v4.0 [9]: 1.1.1 Ensure that code complies with the 2011 ISO C++ Language Standard. HIC++ v4.0 [9]: 1.3.4 Do not use deprecated STL library features.

Rule M1-0-2 (required, toolchain, non-automated)

Multiple compilers shall only be used if they have a common, defined interface. See MISRA C++ 2008 [7] Rule A1-1-2 (required, implementation / toolchain, non-automated)A warning level of the compilation process shall be set in compliance with project policies.

Rationale

If compiler enables the high warning level, then it is able to generate useful warning messages that point out potential run-time problems during compilation time. The information can be used to resolve certain errors before they occur at run-time. Note that it is common practice to turn warnings into errors. Also, note that enabling the highest compiler warning level may produce numerous useless messages during compile time. It is important that the valid warning level for the specific compiler is established in the project.


## See also
JSF December 2005 [8]: AV Rule 218 Compiler warning levels will be set in
compliance with project policies.

Rule A1-1-3 (required, toolchain, non-automated)

An optimization option that disregards strict standard compliance shall not be turned on in the chosen compiler.

Rationale

Enabling optimizations that disregard compliance with the C++ Language Standard may create an output program that should strictly comply to the standard no longer valid.


## See also
none

Rule A1-2-1 (required, toolchain, non-automated)

When using a compiler toolchain (including preprocessor, compiler itself, linker, C++ standard libraries) in safety-related software, the tool confidence level (TCL) shall be determined. In case of TCL2 or TCL3, the compiler shall undergo a “Qualification of a software tool”, as per ISO 26262-8.11.4.6 [6].

Rationale

Vulnerabilities and errors in the compiler toolchain impact the binary that is built.

Example

The following mechanisms could help to increase the Tool error Detection (TD) and thus allowing to reduce the Tool Confidence Level:

  1. Achievement of MC/DC code coverage on generated project assembly code
  2. Diverse implementation of safety requirements at software or even at system level (e.g. two micro-controllers)
  3. Usage of diverse compilers or compilation options
  4. Diversity at the level of operating system
  5. Extensive testing (e.g. equivalence class testing, boundary value testing), testing at several levels (e.g. unit testing, integration testing) Note that in most automotive applications, the compiler is evaluated TCL3 or TCL2. In case of TCL2 or TCL3, the following are typically performed (by compiler vendor or by a project), see table 4 in ISO 26262-8:
  6. Evaluation of the tool development process
  7. Validation of the software tool, by performing automatic compiler tests that are derived from the C++ language specification

## See also
ISO 26262-8 [6]: 11 Confidence in the use of software tools.

Rule A1-4-1 (required, implementation / verification, non-automated)Code metrics and their valid boundaries shall be defined and code
shall comply with defined boundaries of code metrics.

## Rationale
Code metrics that concern i.e. project’s structure, function’s complexity and size of a
source code shall be defined at the project level. It is also important to determine
valid boundaries for each metric to define objectives of the measurement.
Source code metrics needs to be measured for the project and comply with defined
boundaries. This gives valuable information whether the source code is complex,
maintainable and efficient.

See also

HIC++ v4.0 [9]: 8.3.1 Do not write functions with an excessive McCabe Cyclomatic Complexity. HIC++ v4.0 [9]: 8.3.2 Do not write functions with a high static program path count. HIC++ v4.0 [9]: 8.2.2 Do not declare functions with an excessive number of parameters.

Rule A1-4-3 (advisory, implementation, automated)

All code should compile free of compiler warnings.

Rationale

Compiler warnings provide the earliest tool-supported indication of potential problems in source code. Developers should not ignore compiler warnings. Note: Compiler warnings should be turned on to a level matching (as far as possible) the rules in this document, in particular A1-1-1. A possible enforcement of this rule is to turn compiler warnings into errors.

See also

A1-1-1 in section 6.1.1

Rule A2-3-1 (required, architecture / design / implementation, automated)

Only those characters specified in the C++ Language Standard basic source character set shall be used in the source code.

Rationale

The basic source character set consists of 96 characters: the space character, the control characters representing horizontal tab, vertical tab, form feed, and new-line,

plus the following 91 graphical characters:

a b c d e f g h i j k l m n o p q r s t u v w x y z
ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_{}[]#(
) < > % : ; . ? * + - / ^ & | ~ ! =, \ " ’

[C++ Language Standard [3]]

Exception

It is permitted to use other characters inside the text of a wide string and a UTF-8 encoded string literal. It is also permitted to use a character @ inside comments. See rule A2-7-3.

Example

// $Id: A2-3-1.cpp 307578 2018-02-14 14:46:20Z michal.szczepankiewicz $
#include <cstdint>

void Fn() noexcept
{
    std::int32_t sum = 0; // Compliant
                          // std::int32_t £_value = 10; // Non-compliant
                          // sum += £_value; // Non-compliant
                          // Variable sum stores £ pounds // Non-compliant
}

See also

JSF December 2005 [8]: AV Rule 9: Only those characters specified in the C++ basic source character set will be used.

Rule A2-5-1 (required, implementation, automated)

Trigraphs shall not be used.

Rationale

Trigraphs are denoted to be a sequence of 2 question marks followed by a specified third character (e.g. ??’ represents a ~character. They can cause accidental confusion with other uses of two question marks. The Trigraphs are: ??=, ??/, ??’, ??(, ??), ??!, ??<, ??>, ??-.

Example

//% $Id: A2-5-1.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <iostream>
void Fn1()
{
    std::cout << "Enter date ??/??/??"; // Non-compliant, ??/??/?? becomes \\??
                                        // after trigraph translation
}

void Fn2()
{
    std::cout << "Enter date dd/mm/yy"; // Compliant
}

See also

MISRA C++2008: Rule 2-3-1 (Required) Trigraphs shall not be used.

JSF December 2005 [8]: AV Rule 11 Trigraphs will not be used.

HIC++ v4.0 [9]: 2.2.1 Do not use digraphs or trigraphs.

Rule A2-5-2 (required, implementation, automated)

Digraphs shall not be used.

Rationale

The digraphs are: <%, %>, <:, :>, %:, %:%:. The use of digraphs may not meet developer expectations.

Example

//% $Id: A2-5-2.cpp 305382 2018-01-26 06:32:15Z michal.szczepankiewicz $
class A
{
public:
void F2() {}
};

// void fn1(A* a<:10:>) // Non-compliant

// <%
//
a<:0:>->f2();
// %>

void Fn2(A* a[10]) // Compliant, equivalent to the above

{
a[0]->F2();

}

See also

MISRA C++ 2008 [7]: advisory 2-5-1 Digraphs should not be used. JSF December 2005 [8]: 4.4.1 AV Rule 12 The following digraphs will not be used. HIC++ v4.0 [9]: 2.2.1 Do not use digraphs or trigraphs.

Rule M2-7-1 (required, implementation, automated)

The character sequence /* shall not be used within a C-style comment. See MISRA C++ 2008 [7]

Rule A2-7-1 (required, implementation, automated)

The character \ shall not occur as a last character of a C++ comment.

Rationale

If the last character in a single-line C++ comment is , then the comment will continue in the next line. This may lead to sections of code that are unexpectedly commented out.

Example

// $Id: A2-7-1.cpp 305382 2018-01-26 06:32:15Z michal.szczepankiewicz $
#include <cstdint>
void Fn() noexcept
{
std::int8_t idx = 0;
// Incrementing idx before the loop starts // Requirement X.X.X \\
++idx; // Non-compliant - ++idx was unexpectedly commented-out because of \
character occurrence in the end of C++ comment

constexpr std::int8_t limit = 10;
for (; idx <= limit; ++idx)
{
// ...
}

}

See also

none

Rule A2-7-2 (required, implementation, non-automated)

Sections of code shall not be “commented out”.

Rationale

Comments, using both C-style and C++ comments, should only be used to explain aspect of the source code. Code that is commented-out may become out of date, which may lead to confusion while maintaining the code.

Additionally, C-style comment markers do not support nesting, and for this purpose commenting out code is dangerous, see: M2-7-1. Note that the code that is a part of a comment (e.g. for clarification of the usage of the function, for specifying function behavior) does not violate this rule. As it is not possible to determine if a commented block is a textual comment, a code example or a commented-out piece of code, this rule is not enforceable by static analysis tools.

Example

// $Id: A2-7-2.cpp 305382 2018-01-26 06:32:15Z michal.szczepankiewicz $
#include <cstdint>
void Fn1() noexcept
{
std::int32_t i = 0;

/*
//
* ++i; /* incrementing the variable i */
//
/
*
//
// Non-compliant - C-style comments nesting is not supported,
//
compilation error
for (; i < 10; ++i)
{
// ...
}
}
void Fn2() noexcept
{
std::int32_t i = 0;
// ++i; // Incrementing the variable i // Non-compliant - code should not
// be commented-out
for (; i < 10; ++i)
{
// ...
}
}
void Fn3() noexcept
{
std::int32_t i = 0;
++i; // Incrementing the variable i using ++i syntax // Compliant - code
// is not commented-out, but ++i occurs in a
// comment too
for (; i < 10; ++i)
{
// ...
}
}

See also

MISRA C++ 2008 [7]: Rule 2-7-2 Sections of code shall not be “commented out” using C-style comments.

MISRA C++ 2008 [7]: Rule 2-7-3 Sections of code should not be “commented out” using C++ comments.

Rule A2-7-3 (required, implementation, automated)

All declarations of “user-defined” types, static and non-static data members, functions and methods shall be preceded by documentation.

Rationale

Every declaration needs to provide a proper documentation. This is compatible with the C++ standard library documentation. This forces a programmer to provide a clarification for defined types and its data members responsibilities, methods and functions usage, their inputs and outputs specification (e.g. memory management, ownership, valid boundaries), and exceptions that could be thrown.

Example

//% $Id: A2-7-3.hpp 305382 2018-01-26 06:32:15Z michal.szczepankiewicz $
#include <cstdint>

void F1(std::int32_t) noexcept; // Non-compliant documentation

std::int32_t F2(std::int16_t input1,
std::int32_t input2);

// Non-compliant documentation

/// @brief Function description
///
/// @param input1 input1 parameter description
/// @param input2 input2 parameter description
/// @throw std::runtime_error conditions to runtime_error occur
///
/// @return return value description
std::int32_t F3(
std::int16_t input1,
std::int16_t input2) noexcept(false); // Compliant documentation

/// @brief Class responsibility
class C // Compliant documentation
{
public:
/// @brief Constructor description
///
/// @param input1 input1 parameter description
/// @param input2 input2 parameter description
C(std::int32_t input1, float input2) : x{input1}, y{input2} {}

/// @brief Method description
///

/// @return return value descrption

std::int32_t const* GetX() const noexcept { return &x; }

private:
/// @brief Data member descpription
std::int32_t x;
/// @brief Data member descpription
float y;

};

See also

JSF December 2005 [8]: AV Rule 129: Comments in header files should describe the externally visible behavior of the functions or classes being documented.

none

Rule A2-7-5 (required, implementation, non-automated)

Comments shall not document any actions or sources (e.g. tables, figures, paragraphs, etc.) that are outside of the file.

Rationale

Commenting only actions and sources that are inside a particular file reduce dependencies among files. Comments in a file will require changes only when content of the file reworked. Note: This rule does not affect valid assumptions or preconditions for entities within the file.


## See also
JSF December 2005 [8]: AV Rule 128: Comments that document actions or
sources (e.g. tables, figures, paragraphs, etc.) outside of the file being
documented will not be allowed.

Rule A2-8-1 (required, architecture / design /implementation, non-automated)

A header file name should reflect the logical entity for which it provides declarations.

Rationale

Naming a header file with a name of a declared type or accordingly to a collection of free functions or forwarded headers makes include-directives and a project structure more clear and readable.


## See also
JSF December 2005 [8]: AV Rule 55: The name of a header file should reflect
the logical entity for which it provides declarations.

Rule A2-8-2 (advisory, architecture / design /implementation, non-automated)

An implementation file name should reflect the logical entity for which it provides definitions.

Rationale

Naming an implementation file with a name of a declared type or accordingly to a collection of free functions makes a project structure more clear and readable.

See also

JSF December 2005 [8]: AV Rule 56: The name of an implementation file should reflect the logical entity for which it provides definitions and have a “.cpp” extension (this name will normally be identical to the header file that provides the corresponding declarations.).

Rule M2-10-1 (required, architecture / design / implementation,automated)

Different identifiers shall be typographically unambiguous.

See MISRA C++ 2008 [7]

Rule A2-10-1 (required, architecture / design / implementation, automated)

An identifier declared in an inner scope shall not hide an identifier declared in an outer scope.

Rationale

If an identifier is declared in an inner scope and it uses the same name as an identifier that already exists in an outer scope, then the innermost declaration will “hide” the outer one. This may lead to developer confusion. The terms outer and inner scope are defined as follows: Identifiers that have file scope can be considered as having the outermost scope. Identifiers that have block scope have a more inner scope. Successive, nested blocks, introduce more inner scopes.

Note that declaring identifiers in different named namespaces, classes, structs or enum classes will not hide other identifiers from outer scope, because they can be accessed using fully-qualified id.

Exception

An identifier declared within a namespace using the same name as an identifier of the containing namespace does not violate the rule. An identifier declared locally inside a lambda expression and not referring to a name of a captured variable does not violate the rule.

Example

//% $Id: A2-10-1.cpp 313834 2018-03-27 11:35:19Z michal.szczepankiewicz $
#include <cstdint>
std::int32_t sum = 0;
namespace
{
    std::int32_t sum; // Non-compliant, hides sum in outer scope
}
class C1
{
    std::int32_t sum; // Compliant, does not hide sum in outer scope
};
namespace n1
{
    std::int32_t sum; // Compliant, does not hide sum in outer scope
    namespace n2
    {
        std::int32_t sum; // Compliant, does not hide sum in outer scope
    }
}

std::int32_t idx;
void F1(std::int32_t idx)
{
    //Non-compliant, hides idx in outer scope
}

void F2()
{
    std::int32_t max = 5;

    for (std::int32_t idx = 0; idx < max; ++idx) // Non-compliant, hides idx in outer scope
    {
        for (std::int32_t idx = 0; idx < max; ++idx) // Non-compliant, hides idx in outer scope
        {
        }
    }

}
void F3()
{
    std::int32_t i = 0;
    std::int32_t j = 0;
    auto lambda = [i]() {
        std::int32_t j =
            10; // Compliant - j was not captured, so it does not hide
                // j in outer scope
        return i + j;
    };
}

See also

MISRA C++ 2008 [7]: required 2-10-2 Identifiers declared in an inner scope shall not hide an identifier declared in an outer scope.

JSF December 2005 [8]: 4.15 AV Rule 135 Identifiers in an inner scope shall not use the same name as an identifier in an outer scope, and therefore hide that identifier.

HIC++ v4.0 [9]: 3.1.1 Do not hide declarations.

Rule A2-10-6 (required, implementation, automated)

A class or enumeration name shall not be hidden by a variable, function or enumerator declaration in the same scope.

Rationale

C++ Language Standard [3] defines that a class or enumeration name can be hidden by an explicit declaration (of the same name) of a variable, data member, function, or enumerator in the same scope, regardless of the declaration order. Such declarations can be misleading for a developer and can lead to compilation errors.

Example

//% $Id: A2-10-6.cpp 313821 2018-03-27 11:16:14Z michal.szczepankiewicz $
#include <cstdint>

namespace NS1 {
class G {};
void G() {} //non-compliant, hides class G
}

namespace NS2 {
enum class H { VALUE=0, };
std::uint8_t H = 17; //non-compliant, hides
//scoped enum H
}

namespace NS3 {
class J {};
enum H //does not hide NS2::H, but non-compliant to A7-2-3
{
J=0, //non-compliant, hides class J
};
}

int main(void)
{
NS1::G();
//NS1::G a; //compilation error, NS1::G is a function
//after a name lookup procedure
class NS1::G a{}; //accessing hidden class type name

enum NS2::H b ; //accessing scoped enum NS2::H
NS2::H = 7;

class NS3::J c{}; //accessing hidden class type name
std::uint8_t z = NS3::J;

}

See also

ISO/IEC 14882:2014 [3]: 3.3.10.2: [basic.scope.hiding] MISRA C++ 2008 [7]: 2-10-6: If an identifier refers to a type, it shall not also refer to an object or a function in the same scope. HIC++ v4.0 [9]: 3.1.1: Do not hide declarations.

Rule A2-10-4 (required, implementation, automated)

The identifier name of a non-member object with static storage duration or static function shall not be reused within a namespace.

Rationale

No identifier with static storage duration should be re-used in the same namespace across any source files in the project. This may lead to the developer or development tool confusing the identifier with another one.

Example

//% $Id: A2-10-4.cpp 305382 2018-01-26 06:32:15Z michal.szczepankiewicz $
#include <cstdint>
// f1.cpp
namespace ns1
{

static std::int32_t globalvariable = 0;
}

// f2.cpp
namespace ns1
{
// static std::int32_t globalvariable = 0; // Non-compliant - identifier reused
// in ns1 namespace in f1.cpp
}
namespace ns2
{
static std::int32_t globalvariable =
0; // Compliant - identifier reused, but in another namespace
}

// f3.cpp
static std::int32_t globalvariable =
0; // Compliant - identifier reused, but in another namespace

See also

MISRA C++ 2008 [7]: advisory 2-10-5 The identifier name of a non-member object or function with static storage duration should not be reused. Rule A2-10-5 (advisory, design / implementation, automated) Anidentifier name of a function with static storage duration or a non-member object with external or internal linkage should not be reused.

Rationale

Regardless of scope, no identifier with static storage duration should be re-used across any source files in the project. This includes objects or functions with external linkage and any objects or functions with static storage class specifier. While the compiler can understand this, the possibility exists for the developer or development tool to incorrectly associate unrelated variables with the same name. Note: This rule does not apply to objects without linkage, e.g. function local static objects.

Example

//% $Id: A2-10-5.cpp 305382 2018-01-26 06:32:15Z michal.szczepankiewicz $
#include <cstdint>
// f1.cpp
namespace n_s1
{
static std::int32_t globalvariable = 0;
}
static std::int32_t filevariable = 5; // Compliant - identifier not reused
static void Globalfunction();

// f2.cpp
namespace n_s1
{
// static std::int32_t globalvariable = 0; // Non-compliant - identifier reused
static std::int16_t modulevariable = 10; // Compliant - identifier not reused
}
namespace n_s2
{
static std::int16_t modulevariable2 = 20;
}
static void Globalfunction();
// Non-compliant - identifier reused
static std::int16_t modulevariable2 = 15; // Non-compliant - identifier reused

See also

MISRA C++ 2008 [7]: advisory 2-10-5 The identifier name of a non-member object or function with static storage duration should not be reused.

Rule A2-11-1 (required, design / implementation, automated)Volatile keyword shall not be used.

Rationale

The volatile keyword disables compiler optimizations for a particular variable or object’s value in case those values may change in ways not specified by the language (e.g. object representing a hardware register). It is error prone and often misused by developers, as they expect this is equal to variable or object’s value being atomic.

Note: The main intention of this rule is to eliminate incorrect usages of volatile keyword and force developers to precisely document each usage of volatile keyword.


## See also
JSF December 2005 [8]: AV Rule 205: The volatile keyword shall not be used
unless directly interfacing with hardware.
HIC++ v4.0 [9]: 18.2.3: Do not share volatile data between threads.
C++ Core Guidelines [11]: CP.8: Don’t try to use volatile for synchronization.
C++ Core Guidelines [11]: CP.200: Use volatile only to talk to non-C++ memory.

Rule A2-13-1 (required, architecture / design / implementation,automated) Only those escape sequences that are defined in ISO/IEC
## Rationale
The use of an undefined escape sequence leads to undefined behavior. The defined
escape sequences (ISO/IEC 14882:2014) are: \’, \", \?, \\, \a, \b, \f, \n, \r, \t, \v, \<Octal
Number>, \x<Hexadecimal Number>.
Note: Universal-character-names (\u hex-quad and \U hex-quad hex-quad) are also
allowed in character and string literals (although they look similar to escape
sequences, they are handled in a different way by the C++ language, see A2-13-6).
## Example

```cpp
//% $Id: A2-13-1.cpp 305629 2018-01-29 13:29:25Z piotr.serwa $
#include <string>
void F()
{
const std::string
a = "\k";
// Non-compliant
const std::string
b = "\n";
// Compliant
const std::string
c = "\U0001f34c";
// Compliant
}

See also

MISRA C++ 2008 [7]: required 2-13-1 Only those escape sequences that are defined in ISO/IEC14882:2003 shall be used. Rule A2-13-6 (required, architecture / design / implementation,automated) Universal character names shall be used only inside character or string literals.

Rationale

Using universal-character-names to define a language identifier can be confusing for a developer and may be troublesome to use this identifier in the source code.

Example

//% $Id: A2-13-6.cpp 307578 2018-02-14 14:46:20Z michal.szczepankiewicz $
#include <string>
void F()
{
const std::string c = "\U0001f34c"; // Compliant
}

//non-compliant
void \U0001f615()

{
//

}

Rule A2-13-5 (advisory, implementation, automated)

Hexadecimal constants should be upper case.

Rationale

Using upper case literals for hexadecimal constants makes the source code consistent in this matter and removes a potential developer confusion.

Example

//% $Id: A2-13-5.cpp 305629 2018-01-29 13:29:25Z piotr.serwa $

#include <cstdint>

int main(void)
{
std::int16_t a = 0x0f0f; //non-compliant
std::int16_t b = 0x0f0F; //non-compliant
std::int16_t c = 0x0F0F; //compliant

return 0;

}

See also

JSF December 2005 [8]: AV Rule 150: Hexadecimal constants will be represented using all uppercase letters. Rule M2-13-2 (required, architecture / design / implementation,automated) Octal constants (other than zero) and octal escape sequences (other than “\0” ) shall not be used. See MISRA C++ 2008 [7] Rule M2-13-3 (required, architecture / design / implementation,automated) A “U” suffix shall be applied to all octal or hexadecimal integer literals of unsigned type. See MISRA C++ 2008 [7]

Rule M2-13-4 (required, architecture / design / implementation,automated) Literal suffixes shall be upper case. See MISRA C++ 2008 [7]

Rule A2-13-2 (required, implementation, automated)

String literals with different encoding prefixes shall not be concatenated.

Rationale

Concatenation of wide and narrow string literals leads to undefined behavior. “In translation phase 6 (2.2), adjacent string-literals are concatenated. If both stringliterals have the same encoding-prefix, the resulting concatenated string literal has that encoding-prefix. If one string-literal has no encoding-prefix, it is treated as a string-literal of the same encoding-prefix as the other operand. If a UTF-8 string literal token is adjacent to a wide string literal token, the program is ill-formed. Any other concatenations are conditionally-supported with implementation-defined behavior. [ Note: This concatenation is an interpretation, not a conversion. Because the interpretation happens in translation phase 6 (after each character from a literal has been translated into a value from the appropriate character set), a string-literal’s initial rawness has no effect on the interpretation or well-formedness of the concatenation. -end note ]” [C++14 Language Standard] [3]

Example

//% $Id: A2-13-2.cpp 305629 2018-01-29 13:29:25Z piotr.serwa $

char16_t nArray[] =
    u"Hello"
    u"World"; // Compliant, "u" stands for char16_t type

char32_t nArray2[] =
    U"Hello"
    U"World"; // Compliant, "U" stands for char32_t type

wchar_t wArray[] =
    L"Hello"
    L"World"; // Compliant, "L" stands for wchar_t type - violates A2-13-3
              // rule.

wchar_t mixed1[] =
    "Hello"
    L"World"; // Compliant

char32_t mixed2[] =
    "Hello"
    U"World"; // Compliant

char16_t mixed3[] =
    "Hello"
    u"World"; // Compliant

// wchar_t mixed1[] = u"Hello" L"World"; // Non-compliant - compilation error

// char32_t mixed2[] = u"Hello" U"World"; // Non-compliant - compilation error

See also

MISRA C++ 2008 [7]: required 2-13-5 Narrow and wide string literals shall not be concatenated.

HIC++ v4.0 [9]: 2.5.1 Do not concatenate strings with different encoding prefixes

Rule A2-13-3 (required, architecture / design / implementation,automated)

Type wchar_t shall not be used.

Rationale

Width of wchar_t type is implementation-defined. Types char16_t and char32_t should be used instead.

Example

//% $Id: A2-13-3.cpp 305629 2018-01-29 13:29:25Z piotr.serwa $
char16_t string1[] = u"ABC"; // Compliant
char32_t string2[] = U"DEF"; // Compliant
wchar_t string3[] = L"GHI"; // Non-compliant

See also

none

Rule A2-13-4 (required, architecture / design / implementation,automated)

String literals shall not be assigned to non-constant pointers.

Rationale

Since C++0x, there was a change in subclause 2.13.5 for string literals. To prevent from calling an inappropriate function that might modify its argument, the type of a string literal was changed from “array of char” to “array of const char”. Such a usage is deprecated by the Standard and reported by a compiler as a warning. This rule is deliberately redundant, in case rules A1-1-1 and A1-4-3 are disabled in a project.

Example

//% $Id: A2-13-4.cpp 307578 2018-02-14 14:46:20Z michal.szczepankiewicz $

int main(void)
{

    //non-compliant
    char nc2[] = "AUTOSAR"; //compliant with A2-13-4, non-compliant with A18 -1-1

    char nc3[8] = "AUTOSAR"; //compliant with A2-13-4, non-compliant with A18 -1-1

    nc1[3] = ’a’; // undefined behaviour

    char* nc1 = "AUTOSAR";

    //compliant
    const char c2[] = "AUTOSAR"; //compliant with A2-13-4, non-compliant with A18-1-1

    const char c3[8] = "AUTOSAR"; //compliant with A2-13-4, non-compliant with A18-1-1

    //c1[3] = ’a’; //compilation error

    const char* c1 = "AUTOSAR";

    return 0;

}

See also

JSF December 2005 [8]: AV Rule 151.1: A string literal shall not be modified.

Rule A3-1-1 (required, architecture / design / implementation,automated)

It shall be possible to include any header file in multiple translation units without violating the One Definition Rule.

Rationale

A header file is a file that holds declarations used in more than one translation unit and acts as an interface between separately compiled parts of a program. A header file often contains classes, object declarations, enums, functions, inline functions, templates, typedefs, type aliases and macros.

In particular, a header file is not supposed to contain or produce definitions of global objects or functions that occupy storage, especially objects that are not declared “extern” or definitions of functions that are not declared “inline”.

Example

//% $Id: A3-1-1.hpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <cstdint>
void F1();
// Compliant

extern void F2(); // Compliant
void F3()
{
} // Non-compliant
static inline void F4()
{
} // Compliant
template <typename T>
void F5(T)
{
} // Compliant
std::int32_t a; // Non-compliant
extern std::int32_t b; // Compliant
constexpr static std::int32_t c = 10; // Compliant
namespace ns
{
    constexpr static std::int32_t d = 100; // Compliant
    const static std::int32_t e = 50; // Compliant
    static std::int32_t f; // Non-compliant
    static void F6() noexcept; // Non-compliant
}

See also

MISRA C++ 2008 [7]: Rule 3-1-1 It shall be possible to include any header file in multiple translation units without violating the One Definition Rule.

Rule A3-1-2 (required, architecture / design / implementation,automated)

Header files, that are defined locally in the project, shall have a file name extension of one of: ".h", ".hpp" or ".hxx".

Rationale

This is consistent with developer expectations to provide header files with one of the standard file name extensions.

Example

//% $Id: A3-1-2.cpp 266557 2017-02-07 13:08:19Z piotr.tanski $
//#include <h3.h> // Compliant
//#include <h1.hpp> // Compliant
//#include <h2.hxx> // Compliant
//#include <h4.cpp> // Non-compliant
//#include <h5.c> // Non-compliant
//#include <h6.hdr> // Non-compliant
//#include <h7.inc> // Non-compliant

See also

JSF December 2005 [8]: 4.9.2 AV Rule 53 Header files will always have a file name extension of ".h".

Rule A3-1-3 (advisory, architecture / design / implementation,automated)

Implementation files, that are defined locally in the project, should have a file name extension of ".cpp".

Rationale

This is consistent with developer expectations to provide C++ implementation files with the standard file name extension. Note that compilers support various file name extensions for C++ implementation files.

See also

JSF December 2005 [8]: 4.9.2 AV Rule 54 Implementation files will always have a file name extension of ".cpp".

Rule M3-1-2 (required, implementation, automated)

Functions shall not be declared at block scope. See MISRA C++ 2008 [7]

Rule A3-1-4 (required, design / implementation, automated)

When an array with external linkage is declared, its size shall be stated explicitly.

Rationale

Although it is possible to declare an array of incomplete type and access its elements, it is safer to do so when the size of the array can be explicitly determined.

Example

//% $Id: A3-1-4.hpp 271687 2017-03-23 08:57:35Z piotr.tanski $
#include <cstdint>
extern std::int32_t array1[]; // Non-compliant
extern std::int32_t array2[42]; // Compliant

See also

MISRA C++ 2008 [7]: Rule 3-1-3 When an array is declared, its size shall either be stated explicitly or defined implicitly by initialization.

Rule A3-1-5 (required, design, partially-automated)

A function definition shall only be placed in a class definition if (1) the function is intended to be inlined (2) it is a member function template (3) it is a member function of a class template.

Rationale

Merging the implementation into the declaration instructs a compiler to inline the method which may save both time and space for short functions. For templates, it allows to reduce repetitions of template syntax elements (e.g. parameter list), which makes code less difficult to read and maintain.

Example

//% $Id: A3-1-5.cpp 305629 2018-01-29 13:29:25Z piotr.serwa $
#include <cstdint>
#include <iostream>

class A
{
public:
//compliant with (2)
template <typename T>
void Foo(T&& t)
{
std::cout << __PRETTY_FUNCTION__ << " defined inside with param: " << t
<< std::endl;
}

//non-compliant with (2)
template <typename T>
void Bar(T&& t);

//compliant with (1)
std::uint32_t GetVal() const noexcept
{
return val;
}

//non-compliant with (1)
std::uint32_t GetVal2() const noexcept;

private:
std::uint32_t val = 5;
};

template <typename T>
void A::Bar(T&& t)
{
std::cout << __PRETTY_FUNCTION__ << " defined outside with param: " << t << std::endl;

}

std::uint32_t A::GetVal2() const noexcept
{

return val;

}

template <typename T>
class B
{
public:
B(const T& x) : t(x) {}

//compliant with (3)
void display() const noexcept
{
std::cout << t << std::endl;
}

//non-compliant with (3)
void display2() const noexcept;

private:
T t;
};

template <typename T>
void B<T>::display2() const noexcept
{
std::cout << t << std::endl;
}

int main(void)
{
std::uint32_t tmp = 5;
A a;
a.Foo(3.14f);
a.Bar(5);

std::cout << a.GetVal() << std::endl;

B<std::int32_t> b(7);
b.display();

return 0;

}

See also

JSF December 2005 [8]: AV Rule 109: A function definition should not be placed in a class specification unless the function is intended to be inlined.

Rule A3-1-6 (advisory, design, automated)

Trivial accessor and mutator functions should be inlined.

Rationale

Inlining trivial accessors and mutators saves time and space, as it reduces multiple syntax elements that has to be repeated.

Example

//% $Id: A3-1-6.cpp 305629 2018-01-29 13:29:25Z piotr.serwa $
#include <cstdint>

class A
{
public:
A(std::int32_t l) noexcept : limit{l} {}
//compliant
std::int32_t Limit() const noexcept { return limit; }
//compliant
void SetLimit(std::int32_t l) { limit = l; }

//non-compliant
//std::int32_t Limit() const noexcept
//{
//open file, read data, close file
//return value
//}
//non-compliant
//void SetLimit(std::int32_t l)
//{
//open file, write data, close file
//}

private:
std::int32_t limit;
};

See also

JSF December 2005 [8]: AV Rule 122: Trivial accessor and mutator functions should be inlined.

Rule M3-2-1 (required, implementation, automated)

All declarations of an object or function shall have compatible types. See MISRA C++ 2008 [7]

Rule M3-2-2 (required, implementation, automated)

The One Definition Rule shall not be violated. See MISRA C++ 2008 [7]

Rule M3-2-3 (required, implementation, automated)

A type, object or function that is used in multiple translation units shall be declared in one and only one file. See MISRA C++ 2008 [7]

Rule M3-2-4 (required, implementation, automated)

An identifier with external linkage shall have exactly one definition. See MISRA C++ 2008 [7]

Rule A3-3-1 (required, implementation, automated)

Objects or functions with external linkage (including members of named namespaces) shall be declared in a header file.

Rationale

Placing the declarations of objects and functions with external linkage in a header file means that they are intended to be accessible from other translation units. If external linkage is not needed, then the object or function is supposed to be either declared in an unnamed namespace or declared static in the implementation file. This reduces the visibility of objects and functions, which allows to reach a higher encapsulation and isolation. Note that members of named namespace are by default external linkage objects.

Exception

This rule does not apply to main, or to members of unnamed namespaces.

Example

//% $Id: A3-3-1.hpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <cstdint>
extern std::int32_t a1;
extern void F4();

namespace n
{
void F2();
std::int32_t a5; // Compliant, external linkage
}

```cpp
//% $Id: A3-3-1.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include "A3-3-1.hpp"
std::int32_t
a1 = 0;
// Compliant, external linkage
std::int32_t
a2 = 0;
// Non-compliant, static keyword not used
static std::int32_t a3 = 0; // Compliant, internal linkage
namespace
{
std::int32_t a4 = 0; // Compliant by exception
9 void F1()
// Compliant by exception
{
}
}
namespace n
{
void F2() // Compliant, external linkage
{
}
std::int32_t a6 = 0; // Non-compliant, external linkage
}
extern std::int32_t a7; // Non-compliant, extern object declared in .cpp file
static void F3()// Compliant, static keyword used
{
}
void F4() // Compliant, external linkage
{
a1 = 1;
a2 = 1;
a3 = 1;
a4 = 1;
n::a5 = 1;
n::a6 = 1;
a7 = 1;
}
void F5() // Non-compliant, static keyword not used
{
a1 = 2;
a2 = 2;
a3 = 2;
a4 = 2;
n::a5 = 2;
n::a6 = 2;
a7 = 2;
}

int main(int, char**) // Compliant by exception

{

F1();

n::F2();
F3();
F4();
F5();

}

See also

MISRA C++ 2008 [7]: Rule 3-3-1 Objects or functions with external linkage shall be declared in a header file.

Rule A3-3-2 (required, implementation, automated)

Static and thread-local objects shall be constant-initialized.

Rationale

In general, using non-const global and static variables obscures the true dependencies of an API, since they can be accessed from any place of the source code. It therefore makes the code more difficult to maintain, less readable, and significantly less testable. A particular problem is that the order in which constructors and initializers for static variables are called is only partially specified by the C++ Language Standard and can even change from build to build. This can cause issues that are difficult to find or debug.

The compiler performs constant-initialization, if the object is initialized by a constexpr constructor with only constant expression as arguments; or the object is not initialized by a constructor call, but is value-initialized (T object{};); or the object is not initialized by a constructor call, but is initialized by an initializer consisting only of constant expressions. Constant initialization is guaranteed to occur before any other initialization of static or thread-local objects and may happen at compile time. Thus it is guaranteed that problematic dependencies between the initializers of constant-initialized static or thread-local objects cannot occur. Note that declaring a static variable as constexpr (static is implied in this case, but may be added to the declaration), enforces constant initialization by the compiler. Note that the rule applies to: global variables (i.e. extern) static variables static class member variables static function-scope variables

Example

// $Id: A3-3-2.cpp 305690 2018-01-29 14:35:00Z jan.babst $
#include <cstdint>
#include <limits>
#include <string>
class A
{
public:
static std::uint8_t instanceId;
static float const pi;
static std::string const separator;

A() {}
// Implementation...

};
std::uint8_t A::instanceId = 0;// Compliant - constant initialization
float const A::pi = 3.14159265359; // Compliant - constant initialization
std::string const A::separator =
"=========="; // Non-compliant - string c’tor is not constexpr

class C
{
public:
constexpr C() = default;
};

namespace
{
constexpr std::int32_t maxInt32 =
std::numeric_limits<std::int32_t>::max(); // Compliant - constexpr variable

A instance{};
// Compliant - constant (value) initialization
constexpr C c{}; // Compliant - constexpr c’tor call
} // namespace

void Fn() noexcept
{
static A a{}; // Non-compliant - A’s default c’tor is not constexpr
static std::int32_t counter{0};
// Compliant

}

static std::string border(5, ’*’);

// Non-compliant - not a constexpr c’tor

class D
{
public:
D() = default;
D(D const&) = default;
D(D&&) = default;
D& operator=(D const&) = default;
D& operator=(D&&) = default;
~D() = default;

private:

static D* instance;

};

D* D::instance = nullptr; // Compliant - initialization by constant expression

See also

cppreference.com [16]: Constant initialization. HIC++ v4.0 [9]: 3.3.1: Do not use variables with static storage duration. JSF December 2005 [8]: AV Rule 214: Assuming that non-local static objects, in separate translation units, are initialized in a special order shall not be done. SEI CERT C++ Coding Standard [10]: DCL56-CPP: Avoid cycles during initialization of static objects. C++ Core Guidelines [11]: I.22: Avoid complex initialization of global objects. Google C++ Style Guide [12]: Static and Global Variables.

Rule M3-3-2 (required, implementation, automated)

If a function has internal linkage then all re-declarations shall include the static storage class specifier. See MISRA C++ 2008 [7] Note: Static storage duration class specifier is redundant and does not need to be specified if a function is placed in an unnamed namespace.

Rule M3-4-1 (required, implementation, automated)

An identifier declared to be an object or type shall be defined in a block that minimizes its visibility. See MISRA C++ 2008 [7]


## See also
C++ Core Guidelines [11]: ES.21: Don’t introduce a variable (or constant)
before you need to use it.

Rule A3-8-1 (required, implementation, not automated)

An object shall not be accessed outside of its lifetime.

Rationale

Accessing an object outside of its lifetime, i.e. before its initialization or constructor has completed, or after its non-trivial destructor has finished, is well defined only for a very restricted number of cases, as laid out by the language standard. Outside of these cases it leads to undefined behavior. Note: The AUTOSAR C++14 guidelines contain several other rules which are special cases of this rule (see references below). This rule was added to provide generic coverage for all cases not contained in these specialized rules. This also makes it easier to provide tracing from other standards with a similar generic rule. Note: The examples given below are not intended to represent a complete list of situations where violations of this rule can occur.

Example

//% $Id: A3-8-1.cpp 305786 2018-01-30 08:58:33Z michal.szczepankiewicz $

//
// 1. Pointer to virtual base is passed as function argument after lifetime of
// object has ended.
//

class B
{
};

class C1 : public virtual B // violates M10-1-1
{
};

class C2 : public virtual B // violates M10-1-1
{
};

class D : public C1, public C2
{
};

void f(B const* b){};

void example1()
{

D* d = new D(); // lifetime of d starts (violates A18-5-2)

// Use d
delete d; // lifetime of d ends (violates A18-5-2)

f(d); // Non-compliant - Undefined behavior, even if argument is not used
// by f().

}

//
// 2. Accessing an initializer_list after lifetime of initializing array has
// ended.
//
class E
{
std::initializer_list<int> lst;

public:
// Conceptually, this works as if a temporary array {1, 2, 3} was created
// and a reference to this array was passed to the initializer_list. The
// lifetime of the temporary array ends when the constructor finishes.
E() : lst{1, 2, 3} {}

int first() const { return *lst.begin(); }

};

void example2()
{
E e;
std::out << e.first() << "\n"; // Non-compliant
}

//
// 3. Exiting main while running tasks depend on static objects
//
void initialize_task()
{
// start some task (separate thread) which depends on some static object.
// ...
}

int main()
{
// static constructors are called

initialize_task();
} // main ends, static destructors are called

// Non-compliant
// Task begins to run and accesses destroyed static object.

//
// 4. Storage reuse without explicit destructor call
//
void example4()
{

std::string str;
new (&a) std::vector<int>{}; // Non-compliant: storage of str reused without
// calling its non-trivial destructor.
} // Non-compliant: Destructor of str is implicitly called at scope exit, but
// storage contains object of different type.

See also

ISO/IEC 14882:2014 [3]: 3.8: [basic.life] JSF December 2005 [8]: AV Rule 70.1: An object shall not be improperly used before its lifetime begins or after its lifetime ends. SEI CERT C++ Coding Standard [10]: EXP54-CPP: Do not access an object outside of its lifetime. A5-1-4 in section 6.5.1 M7-5-1 in section 6.7.5 M7-5-2 in section 6.7.5 A7-5-1 in section 6.7.5 M12-1-1 in section 6.12.1

Rule M3-9-1 (required, implementation, automated)

The types used for an object, a function return type, or a function parameter shall be token-for-token identical in all declarations and re-declarations. See MISRA C++ 2008 [7]

Rule A3-9-1 (required, implementation, automated)

Fixed width integer types from , indicating the size and signedness, shall be used in place of the basic numerical types.

Rationale

The basic numerical types of char, int, short, long are not supposed to be used, specific-length types from header need be used instead. Fixed width integer types are: std::int8_t std::int16_t

std::int32_t std::int64_t std::uint8_t std::uint16_t std::uint32_t std::uint64_t

Exception

The wchar_t does not need a typedef as it always maps to a type that supports wide characters.

Example

//% $Id: A3-9-1.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <cstdint>
void F()
{
std::int32_t
i1 = 5;
// Compliant
int i2 = 10;
// Non-compliant
std::int64_t i3 = 250; // Compliant
long int i4
= 50;
// Non-compliant
std::int8_t
i5 = 16;
// Compliant
char
i6 = 23;
// Non-compliant
}

See also

MISRA C++ 2008 [7]: Rule 3-9-2 typedefs that indicate size and signedness should be used in place of the basic numerical types.

Rule M3-9-3 (required, implementation, automated)

The underlying bit representations of floating-point values shall not be used. See MISRA C++ 2008 [7]

Rule M4-5-1 (required, implementation, automated)

Expressions with type bool shall not be used as operands to built-in operators other than the assignment operator =, the logical operators

&&, ||, !, the equality operators == and ! =, the unary & operator, and the

conditional operator.

See MISRA C++ 2008 [7]

Rule A4-5-1 (required, implementation, automated)

Expressions with type enum or enum class shall not be used as operands to built-in and overloaded operators other than the subscript operator [ ], the assignment operator =, the equality operators == and ! =, the unary & operator, and the relational operators <, <=, >, >=.

Rationale

Enumerations, i.e. enums or enum classes, have implementation-defined representations and they are not supposed to be used in arithmetic contexts. Note that only enums can be implicitly used as operands to other built-in operators, like operators +, , , etc. Enum class needs to provide definitions of mentioned operators in order to be used as operand.

Exception

It is allowed to use the enumeration as operand to all built-in and overloaded operators if the enumeration satisfies the “BitmaskType” concept [16].

Example

// $Id: A4-5-1.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <cstdint>
enum Colour : std::uint8_t
{
Red,
Green,
Blue,
ColoursCount
};
void F1() noexcept(false)
{
Colour colour = Red;
if (colour == Green) // Compliant
{
}

if (colour == (Red + Blue)) // Non-compliant
{
}

if (colour < ColoursCount) // Compliant
{
}

}
enum class Car : std::uint8_t
{
Model1,
Model2,
Model3,
ModelsCount
};
void F2() noexcept(false)
{
Car car = Car::Model1;
if (car != Car::Model2) // Compliant
{
}

if (car == Car::Model3) // Compliant
{
}

// if (car == (Car::Model1 + Car::Model2)) // Non-compliant // operator+ not provided for Car enum class, compilation error
//{
//}
if (car < Car::ModelsCount) // Compliant
{
}
}
Car operator+(Car lhs, Car rhs)
{
return Car::Model3;
}
void F3() noexcept(false)
{
Car car = Car::Model3;
if (car == (Car::Model1 + Car::Model2)) // Non-compliant - overloaded
// operator+ provided, no
// compilation error
{
}
}
enum Team : std::uint8_t
{
TeamMember1 = 0,
TeamMember2 = 1,
TeamMember3 = 2,
TeamMember4 = 3,
TeamMembersStart = TeamMember1,
TeamMembersEnd = TeamMember2,
TeamMembersCount = 4
};
void F4(const char* teamMember)

{

// Implementation
}
void F5()
{

const char* team[TeamMembersCount]; // Compliant

// ...
F4(team[TeamMember2]); // Compliant

}

See also

MISRA C++ 2008 [7]: Rule 4-5-2 Expressions with type enum shall not be used as operands to built-in operators other than the subscript operator [ ], the assignment operator =, the equality operators == and !=, the unary & operator, and the relational operators <, <=, >, >=.

Rule M4-5-3 (required, implementation, automated)

Expressions with type (plain) char and wchar_t shall not be used as operands to built-in operators other than the assignment operator =, the equality operators == and ! =, and the unary & operator. See MISRA C++ 2008 [7]

Rule A4-7-1 (required, implementation, automated)

An integer expression shall not lead to data loss.

Rationale

Implicit conversions, casts and arithmetic expressions may lead to data loss, e.g. overflows, underflows or wrap-around. Integral expressions need to be performed on proper integral types that ensure that the data loss will not occur or appropriate guards should be used to statically detect or counteract such a data loss.

Example

// $Id: A4-7-1.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <cstdint>
#include <stdexcept>
std::int8_t Fn1(std::int8_t x, std::int8_t y) noexcept
{
return (x + y); // Non-compliant - may lead to overflow

}
std::int8_t Fn2(std::int8_t x, std::int8_t y)
{
if (x > 100 || y > 100) // Range check
{
throw std::logic_error("Preconditions check error");
}
return (x + y); // Compliant - ranges of x and y checked before the
// arithmetic operation
}
std::int16_t Fn3(std::int8_t x, std::int8_t y) noexcept
{
return (static_cast<std::int16_t>(x) + y); // Compliant - std::int16_t type
// is enough
// operation
}
std::uint8_t Fn4(std::uint8_t x, std::uint8_t y) noexcept
{

for this arithmetic

return (x * y); // Non-compliant - may lead to wrap-around

}
std::int8_t Fn5(std::int16_t x)
{
return static_cast<std::int8_t>(x); // Non-compliant - data loss
}
std::int8_t Fn6(std::int16_t x)
{
return x; // Non-compliant - data loss by implicit conversion
}
void F()
{
std::int8_t x1 =
Fn1(5, 10); // Compliant - overflow will not occur for these values
std::int8_t x2 = Fn1(250, 250); // Non-compliant - Overflow occurs
try
{
std::int8_t x3 =
Fn2(250, 250); // Compliant - No overflow, range checks
// inside fn2() function
}
catch (std::logic_error&)
{
// Handle an error
}
std::int16_t x4 = Fn3(250, 250); // Compliant - No overflow, arithmetic
// operation underlying type is wider than
// std::int8_t
std::uint8_t x5 = Fn4(50, 10);// Non-compliant - Wrap-around occurs
std::int8_t x6 = Fn5(100);// Compliant - data loss will not occur
std::int8_t x7 = Fn5(300);// Non-compliant - Data loss occurs
std::int8_t x8 = Fn6(300);// Non-compliant - Data loss occurs

std::int8_t x9 = 150;
std::int16_t x10 = static_cast<std::int16_t>(x9 + x9); // Non-compliant
x10 = x9 + x9;
x10 = static_cast<std::int16_t>(x9) + x9;

// Non-compliant
// Compliant

std::int8_t x11 = x9 << 5; // Non-compliant

std::int8_t x12 = 127;
++x12; // Non-compliant

std::uint8_t x13 = 255;
++x13; // Non-compliant

}

See also

MISRA C++ 2008 [7]: Rule 5-0-6 An implicit integral or floating-point conversion shall not reduce the size of the underlying type. MISRA C++ 2008 [7]: Rule 5-0-8 An explicit integral or floating-point conversion shall not increase the size of the underlying type of a cvalue expression. HIC++ v4.0 [9]: 4.2.2 Ensure that data loss does not demonstrably occur in an integral expression. JSF December 2005 [8]: AV Rule 212: Underflow or overflow functioning shall not be depended on in any special way. C++ Core Guidelines [11]: ES.46: Avoid lossy (narrowing, truncating) arithmetic conversions.

Rule M4-10-1 (required, implementation, automated)

NULL shall not be used as an integer value. See MISRA C++ 2008 [7] Rule A4-10-1 (required, architecture / design / implementation,automated) Only nullptr literal shall be used as the null-pointer-constant.

Rationale

In C++, the literal NULL is both the null-pointer-constant and an integer type. To meet developer expectations, only nullptr pointer literal shall be used as the null-pointerconstant.

Note that, nullptr pointer literal allows parameters forwarding via a template function.

Example

//% $Id: A4-10-1.cpp 298086 2017-11-24 11:13:27Z michal.szczepankiewicz $
#include <cstddef>
#include <cstdint>

void F1(std::int32_t);

void F2(std::int32_t*);

void F3()
{
F1(0);// Compliant
F1(NULL); // Non-compliant - NULL used as an integer,
// compilable
// f1(nullptr); // Non-compliant - nullptr used as an integer
// compilation error
F2(0);// Non-compliant - 0 used as the null pointer constant
F2(NULL);
// Non-compliant - NULL used as the null pointer constant
F2(nullptr); // Compliant
}

void F4(std::int32_t*);

template <class F, class A>
void F5(F f, A a)
{
F4(a);
}
void F6()
{
// f5(f4, NULL); // Non-compliant - function f4(std::int32_t) not declared
F5(F4, nullptr); // Compliant
}

See also

HIC++ v4.0 [9]: 2.5.3 Use nullptr for the null pointer constant

Rule M4-10-2 (required, implementation, automated)

Literal zero (0) shall not be used as the null-pointer-constant. See MISRA C++ 2008 [7]

Rule A5-0-1 (required, implementation, automated)

The value of an expression shall be the same under any order of evaluation that the standard permits.

Rationale

Apart from a few operators (notably &&, ||, ?: and ,) the order in which sub-expressions are evaluated is unspecified and can vary. This means that no reliance can be placed on the order of evaluation of sub-expressions and, in particular, no reliance can be placed on the order in which side effects occur. Those points in the evaluation of an expression at which all previous side effects can be guaranteed to have taken place are called “sequencing”. Sequencing and side effects are described in Section 1.9(7) of ISO/IEC 14882:2014 [3]. Note that the “order of evaluation” problem is not solved by the use of parentheses, as this is not a precedence issue.

Example

// $Id: A5-0-1.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <cstdint>
#include <stack>
// The following notes give some guidance on how dependence on order of
// evaluation may occur, and therefore may assist in adopting the rule.

// 1) Increment or decrement operators
// As an example of what can go wrong, consider
void F1(std::uint8_t (&arr)[10], std::uint8_t idx) noexcept(false)
{
std::uint16_t x = arr[idx] + idx++;
}
// This will give different results depending on whether arr[idx] is evaluated
// before idx++ or vice versa. The problem could be avoided by putting the
// increment operation in a separate statement. For example:
void F2(std::uint8_t (&arr)[10], std::uint8_t idx) noexcept(false)
{
std::uint8_t x = arr[idx] + idx;
idx++;
}

// 2) Function arguments
// The order of evaluation of function arguments is unspecified.
extern std::uint8_t Func(std::uint8_t x, std::uint8_t y);
void F3() noexcept(false)
{
std::uint8_t i = 0;
std::uint8_t x = Func(i++, i);
}
// This will give different results depending on which of the functions two
// parameters is evaluated first.

// 3) Function pointers
// If a function is called via a function pointer there shall be no
// dependence
// on the order in which function-designator and function arguments are
// evaluated.
struct S
{
void TaskStartFn(S* obj) noexcept(false);

};

void F4(S* p) noexcept(false)

{
p->TaskStartFn(p++);

}

// 4) Function calls
// Functions may have additional effects when they are called (e.g. modifying
// some global data). Dependence on order of evaluation could be avoided by
// invoking the function prior to the expression that uses it, making use of a
// temporary variable for the value. For example:
extern std::uint16_t G(std::uint8_t) noexcept(false);
extern std::uint16_t Z(std::uint8_t) noexcept(false);
void F5(std::uint8_t a) noexcept(false)
{
std::uint16_t x = G(a) + Z(a);
}
// could be written as
void F6(std::uint8_t a) noexcept(false)
{
std::uint16_t x = G(a);
x += Z(a);
}
// As an example of what can go wrong, consider an expression to take two values
// off a stack, subtract the second from the first, and push the result back on
// the stack:
std::int32_t Pop(std::stack<std::int32_t>& s)
{
std::int32_t ret = s.top();
s.pop();
return ret;
}
void F7(std::stack<std::int32_t>& s)
{
s.push(Pop(s) - Pop(s));
}
// This will give different results depending on which of the pop() function
// calls is evaluated first (because pop() has side effects).

// 5) Nested assignment statements
// Assignments nested within expressions cause additional side effects. The best
// way to avoid any possibility of this leading to a dependence on order of
// evaluation is not to embed assignments within expressions. For example, the

// following is not recommended:
void F8(std::int32_t& x) noexcept(false)
{
std::int32_t y = 4;
x = y = y++; // It is undefined whether the final value of y is 4 or 5
}
// 6) Accessing a volatile
// The volatile type qualifier is provided in C++ to denote objects whose value
// can change independently of the execution of the program (for example an
// input register). If an object of volatile qualified type is accessed this may
// change its value. C++ compilers will not optimize out reads of a volatile. In
// addition, as far as a C++ program is concerned, a read of a volatile has a
// side effect (changing the value of the volatile). It will usually be
// necessary to access volatile data as part of an expression, which then means
// there may be dependence on order of evaluation. Where possible, though, it is
// recommended that volatiles only be accessed in simple assignment statements,
// such as the following:
void F9(std::uint16_t& x) noexcept(false)
{
volatile std::uint16_t v;
// ...
x = v;
}

// The rule addresses the order of evaluation problem with side effects. Note
// that there may also be an issue with the number of times a sub-expression is
// evaluated, which is not covered by this rule. This can be a problem with
// function invocations where the function is implemented as a macro. For
// example, consider the following function-like macro and its invocation:
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
// ...
void F10(std::uint32_t& i, std::uint32_t j)
{
std::uint32_t z = MAX(i++, j);
}
// The definition evaluates the first parameter twice if a > b but only once if
// a = b. The macro invocation may thus increment i either once or twice,
// depending on the values of i and j.
// It should be noted that magnitude-dependent effects, such as those due to
// floating-point rounding, are also not addressed by this rule. Although
// the
// order in which side effects occur is undefined, the result of an operation is
// otherwise well-defined and is controlled by the structure of the expression.
// In the following example, f1 and f2 are floating-point variables; F3, F4
// and
// F5 denote expressions with floating-point types.

// f1 = F3 + ( F4 + F5 );
// f2 = ( F3 + F4 ) + F5;

// The addition operations are, or at least appear to be, performed in the order

// determined by the position of the parentheses, i.e. firstly F4 is added to F5
// then secondly F3 is added to give the value of f1. Provided that F3, F4 and
// F5 contain no side effects, their values are independent of the order in
// which they are evaluated. However, the values assigned to f1 and f2 are not
// guaranteed to be the same because floating-point rounding following the
// addition operations are dependent on the values being added.

See also

MISRA C++ 2008 [7]: Rule 5-0-1 The value of an expression shall be the same under any order of evaluation that the standard permits HIC++ v4.0 [9]: 5.1.2: Do not rely on the sequence of evaluation within an expression. C++ Core Guidelines [11]: ES.40: Avoid complicated expressions C++ Core Guidelines [11]: ES.43: Avoid expressions with undefined order of evaluation. C++ Core Guidelines [11]: ES.44: Don’t depend on order of evaluation of function arguments. C++ Core Guidelines [11]: R.13: Perform at most one explicit resource allocation in a single expression statement.

Rule M5-0-2 (advisory, implementation, partially automated)

Limited dependence should be placed on C++ operator precedence rules in expressions. See MISRA C++ 2008 [7]


## See also
C++ Core Guidelines [11]: ES.41: If in doubt about operator precedence,
parenthesize

Rule M5-0-3 (required, implementation, automated)

A cvalue expression shall not be implicitly converted to a different underlying type. See MISRA C++ 2008 [7]

Rule M5-0-4 (required, implementation, automated)

An implicit integral conversion shall not change the signedness of the underlying type.

See MISRA C++ 2008 [7]

Rule M5-0-5 (required, implementation, automated)

There shall be no implicit floating-integral conversions.

See MISRA C++ 2008 [7]

Rule M5-0-6 (required, implementation, automated)

An implicit integral or floating-point conversion shall not reduce the size of the underlying type. See MISRA C++ 2008 [7]

Rule M5-0-7 (required, implementation, automated)

There shall be no explicit floating-integral conversions of a cvalue expression. See MISRA C++ 2008 [7] Note: Standard library functions, i.e. std::floor and std::ceil, return a floating-point data type:

#include #include

void Fn() noexcept { float f = -4.5; std::int8_t x1 = static_caststd::int8_t(f); // Compliant, x1 = -4 std::int8_t x2 = static_caststd::int8_t(std::floor(f)); // Compliant, x2 = -5 std::int8_t x3 = static_caststd::int8_t(std::ceil(f)); // Compliant, x3 = -4 }

Rule M5-0-8 (required, implementation, automated)

An explicit integral or floating-point conversion shall not increase the size of the underlying type of a cvalue expression. See MISRA C++ 2008 [7]

Rule M5-0-9 (required, implementation, automated)

An explicit integral conversion shall not change the signedness of the underlying type of a cvalue expression. See MISRA C++ 2008 [7]

Rule M5-0-10 (required, implementation, automated)

If the bitwise operators ~and << are applied to an operand with an underlying type of unsigned char or unsigned short, the result shall be immediately cast to the underlying type of the operand. See MISRA C++ 2008 [7]

Rule M5-0-11 (required, implementation, automated)

The plain char type shall only be used for the storage and use of character values. See MISRA C++ 2008 [7]

Rule M5-0-12 (required, implementation, automated)

Signed char and unsigned char type shall only be used for the storage and use of numeric values. See MISRA C++ 2008 [7]

Rule A5-0-2 (required, implementation, automated)

The condition of an if-statement and the condition of an iteration statement shall have type bool.

Rationale

If an expression with type other than bool is used in the condition of an if-statement or iteration-statement, then its result will be implicitly converted to bool. The condition expression shall contain an explicit test (yielding a result of type bool) in order to clarify the intentions of the developer. Note that if a type defines an explicit conversion to type bool, then it is said to be “contextually converted to bool” (Section 4.0(4) of ISO/IEC 14882:2014 [3]) and can be used as a condition of an if-statement or iteration statement.

Exception

A condition of the form type-specifier-seq declarator is not required to have type bool. This exception is introduced because alternative mechanisms for achieving the same effect are cumbersome and error-prone.

Example

// $Id: A5-0-2.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <cstdint>
#include <memory>

extern std::int32_t* Fn();
extern std::int32_t Fn2();
extern bool Fn3();
void F() noexcept(false)
{
std::int32_t* ptr = nullptr;

while ((ptr = Fn()) != nullptr) // Compliant
{
// Code
}

// The following is a cumbersome but compliant example
do
{
std::int32_t* ptr = Fn();

if (nullptr == ptr)
{
break;
}

// Code
} while (true); // Compliant

std::unique_ptr<std::int32_t> uptr;
if (!uptr) // Compliant - std::unique_ptr defines an explicit conversion to
// type bool.
{
// Code
}

while (std::int32_t length = Fn2()) // Compliant by exception
{
// Code
}

while (bool flag = Fn3()) // Compliant
{
// Code
}

if (std::int32_t* ptr = Fn())

; // Compliant by exception

if (std::int32_t length = Fn2())
; // Compliant by exception

if (bool flag = Fn3())
; // Compliant

std::uint8_t u = 8;

if (u)

; // Non-compliant

bool boolean1 = false;
bool boolean2 = true;

if (u && (boolean1 <= boolean2))
; // Non-compliant

for (std::int32_t x = 10; x; --x)
; // Non-compliant

}

See also

MISRA C++ 2008 [7]: 5-0-13 The condition of an if-statement and the condition of an iteration statement shall have type bool.

Rule M5-0-14 (required, implementation, automated)

The first operand of a conditional-operator shall have type bool.

See MISRA C++ 2008 [7]

Rule M5-0-15 (required, implementation, automated)

Array indexing shall be the only form of pointer arithmetic.

See MISRA C++ 2008 [7]

Rule M5-0-16 (required, implementation, automated)

A pointer operand and any pointer resulting from pointer arithmetic using that operand shall both address elements of the same array. See MISRA C++ 2008 [7] Note: The next element beyond the end of an array indicates the end of the array.

Rule M5-0-17 (required, implementation, automated)

Subtraction between pointers shall only be applied to pointers that address elements of the same array. See MISRA C++ 2008 [7]

Rule A5-0-4 (required, implementation, automated)

Pointer arithmetic shall not be used with pointers to non-final classes.

Rationale

Pointer arithmetic is only well defined if the pointed-to type of the pointer equals the element type of the array it points into, otherwise the behavior is undefined. This property can only be guaranteed if the pointer operand is a pointer to non-class type or a pointer to final class type. Note: This also applies to the subscripting operator as E1[E2] is defined in terms of pointer arithmetic as *((E1)+(E2)).

Example

// $Id: A5-0-4.cpp 309849 2018-03-02 09:36:31Z christof.meerwald $
#include <algorithm>
#include <array>
#include <cstdint>
#include <cstdlib>
#include <memory>
#include <vector>

class Base
{
public:
virtual ~Base() noexcept = 0;
virtual void Do() = 0;
};

class Derived1 final : public Base
{
public:
void Do() final
{
// ...
}

private:
std::int32_t m_value { 0 };

};

class Derived2 final : public Base
{
public:
void Do() final
{
// ...
}

private:

std::string m_value { };

};

void Foo(Base *start, size_t len)

{

// Non-Compliant: pointer arithmetic on non-final pointer type

for (Base *iter = start; iter != start + len; ++iter)

{
iter->Do();

}

}

void Foo(const std::vector<std::unique_ptr<Base>> &v)
{
// Compliant: uses std::unique_ptr for polymorphic objects
std::for_each(v.begin(), v.end(),
[] (const std::unique_ptr<Base> &ptr) {
ptr->Do();
});
}

void DoOpt(Base *obj)

{
if (obj != nullptr)
{
obj->Do();
}

}

void Bar()
{
std::array<Derived1, 2> arr1;

Base *base1 { arr1.data() };

Foo(base1, arr1.size());

DoOpt(&arr1[1]);
DoOpt(&base1[1]);

// Compliant: pointer arithmetic on final class
// Non-Compliant: pointer arithmetic on base class

std::array<Derived2, 2> arr2;

Base *base2 { arr2.data() };

Foo(base2, arr2.size());

DoOpt(arr2.data() + 1); // Compliant: pointer arithmetic on final class
DoOpt(base2 + 1);// Non-Compliant: pointer arithmetic on base class

std::vector<std::unique_ptr<Base>> v;
v.push_back(std::make_unique<Derived1>());
v.push_back(std::make_unique<Derived2>());

Foo(v);

}

See also

SEI CERT C++ Coding Standard [10]: CTR56-CPP: Do not use pointer arithmetic on polymorphic objects. JSF December 2005 [8]: AV Rule 96: Arrays shall not be treated polymorphically. C++ Core Guidelines [11]: T.82: Do not mix hierarchies and arrays.

Rule M5-0-18 (required, implementation, automated)

, >=, <, <= shall not be applied to objects of pointer type, except where they point to the same array. See MISRA C++ 2008 [7]

Rule A5-0-3 (required, implementation, automated)

The declaration of objects shall contain no more than two levels of pointer indirection.

Rationale

Use of more than two levels of indirection can seriously impair the ability to understand the behavior of the code, and therefore should be avoided.

Example

// $Id: A5-0-3.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <cstdint>

using IntPtr = std::int8_t*;

struct S
{

std::int8_t* s1;

std::int8_t** s2;

// Compliant
// Compliant

std::int8_t*** s3;

// Non-compliant

};

S* ps1;

// Compliant

S** ps2;

// Compliant

S*** ps3; // Non-compliant

std::int8_t**

(*pfunc1)();

// Compliant

std::int8_t**

(**pfunc2)();

// Compliant

std::int8_t** (***pfunc3)(); // Non-compliant

std::int8_t*** (**pfunc4)(); // Non-compliant

void Fn(std::int8_t* par1,
std::int8_t** par2,

// Compliant
// Compliant

Guidelines for the use of the C++14 language in
critical and safety-related systems

std::int8_t*** par3,

// Non-compliant

IntPtr* par4,

IntPtr* const* const par5,

std::int8_t* par6[],

// Compliant
// Non-compliant
// Compliant

std::int8_t** par7[])

// Non-compliant

{

std::int8_t* ptr1;

std::int8_t** ptr2;

std::int8_t*** ptr3;

IntPtr* ptr4;

IntPtr* const* const ptr5 = nullptr;

std::int8_t* ptr6[10];

// Compliant
// Compliant
// Non-compliant
// Compliant
// Non-compliant
// Compliant

std::int8_t** ptr7[10];

// Compliant

}

// Explanation of types
// 1) par1 and ptr1 are of type pointer to std::int8_t.
// 2) par2 and ptr2 are of type pointer to pointer to std::int8_t.
// 3) par3 and ptr3 are of type pointer to a pointer to a pointer
// to std::int8_t.
// This is three levels and is non-compliant.
// 4) par4 and ptr4 are expanded to a type of pointer to a pointer to
// std::int8_t.
// 5) par5 and ptr5 are expanded to a type of const pointer to a const
// pointer
// to a pointer to std::int8_t. This is three levels and is non-compliant.
// 6) par6 is of type pointer to pointer to std::int8_t because arrays
// are converted
// to a pointer to the initial element of the array.
// 7) ptr6 is of type pointer to array of std::int8_t.
// 8) par7 is of type pointer to pointer to pointer to
// std::int8_t because arrays are
// converted to a pointer to the initial element of the array. This is
// three
// levels and is non-compliant.
// 9) ptr7 is of type array of pointer to pointer to std::int8_t. This
// is compliant.

See also

MISRA C++ 2008 [7]: 5-0-19 The declaration of objects shall contain no more than two levels of pointer indirection. Rule M5-0-20 (required, implementation, automated) Non-constant operands to a binary bitwise operator shall have the same underlying type. See MISRA C++ 2008 [7]

Rule M5-0-21 (required, implementation, automated)

Bitwise operators shall only be applied to operands of unsigned underlying type. See MISRA C++ 2008 [7]

Rule A5-1-1 (required, implementation, partially automated)

Literal values shall not be used apart from type initialization, otherwise symbolic names shall be used instead.

Rationale

Avoid use of “magic” numbers and strings in expressions in preference to constant variables with meaningful names. Literal values are supposed to be used only in type initialization constructs, e.g. assignments and constructors. The use of named constants improves both the readability and maintainability of the code.

Exception

It is allowed to use literal values in combination with logging mechanism.

Example

// $Id: A5-1-1.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <array>
#include <cstdint>
#include <iostream>
#include <stdexcept>
namespace
{
const std::int32_t maxIterations = 10;
// Compliant - assignment
const char* const loopIterStr = "iter "; // Compliant - assignment

const char separator = ’:’;
// Compliant - assignment
}
void F1() noexcept
{
for (std::int32_t i = 0; i < 10; ++i) // Non-compliant
{
std::cout << "iter " << i << ’:’ << ’\n’; // Compliant by exception
}

for (std::int32_t i = 0; i < maxIterations; ++i) // Compliant
{
std::cout << loopIterStr << i << separator << ’\n’; // Compliant

}

for (std::int32_t i = 0; i < maxIterations; ++i) // Compliant
{
std::cout << "iter " << i << ’:’ << ’\n’; // Compliant by exception
}

}
void F2()
{
// ...
throw std::logic_error("Logic Error"); // Compliant
// initialization of exception object
}
class C
{
public:
C() : x(0), y(nullptr) // Compliant - initialization
{
}
C(std::int8_t num, std::int32_t* ptr) : x(num), y(ptr) {}

private:
std::int8_t x;

std::int32_t* y;

};

static std::int32_t* globalPointer = nullptr; // Compliant - assignment

void F3() noexcept
{
C c1;
// ...
C c2(0, globalPointer); // Compliant - initialization of C object
}
std::int32_t F4(std::int32_t x, std::int32_t y) noexcept
{
return x + y;
}
void F5() noexcept
{
std::int32_t ret = F4(2, 5); // Non-compliant
// ...
std::int32_t x = 2;
std::int32_t y = 5;
ret = F4(x, y); // Compliant

std::array<std::int8_t, 5> arr{{1, 2, 3, 4, 5}}; // Compliant

}

See also

HIC++ v4.0 [9]: 5.1.1 Use symbolic names instead of literal values in code.

Rule A5-1-2 (required, implementation, automated)

Variables shall not be implicitly captured in a lambda expression.

Rationale

Capturing variables explicitly helps document the intention of the author. It also allows for different variables to be explicitly captured by copy or by reference within the lambda definition.

Exception

It is allowed to implicitly capture variables with non-automatic storage duration.

Example

// $Id: A5-1-2.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <algorithm>
#include <cstdint>
#include <vector>
void Fn1(const std::vector<std::int32_t>& v)
{
std::uint64_t sum = 0;
std::for_each(v.begin(), v.end(), [&](std::int32_t lhs) {
sum += lhs;
}); // Non-compliant

sum = 0;
std::for_each(v.begin(), v.end(), [&sum](std::int32_t lhs) {
sum += lhs;
}); // Compliant
}
void Fn2()
{
constexpr std::uint8_t n = 10;
static std::int32_t j = 0;
[n]() {
std::int32_t array[n]; // Compliant
j += 1;
// Compliant by exception
};
}

See also

HIC++ v4.0 [9]: 5.1.4 Do not capture variables implicitly in a lambda. C++ Core Guidelines [11]: F.54: If you capture this, capture all variables explicitly (no default capture).

Rule A5-1-3 (required, implementation, automated)

Parameter list (possibly empty) shall be included in every lambda expression.

Rationale

The lambda-declarator is optional in a lambda expression and results in a closure that can be called without any parameters. To avoid any visual ambiguity with other C++ constructs, it is recommended to explicitly include (), even though it is not strictly required.

Example

// $Id: A5-1-3.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <cstdint>
void Fn()
{
std::int32_t i = 0;
std::int32_t j = 0;
auto lambda1 = [&i, &j] { ++i, ++j; }; // Non-compliant
auto lambda2 = [&i, &j]() {
++i;
++j;
}; // Compliant
}

See also

HIC++ v4.0 [9]: 5.1.5 Include a (possibly empty) parameter list in every lambda expression

Rule A5-1-4 (required, implementation, automated)

A lambda expression object shall not outlive any of its referencecaptured objects.

Rationale

When an object is captured by reference in a lambda, lifetime of the object is not tied to the lifetime of the lambda. If a lambda object leaves the scope of one of its reference-captured object, the execution of the lambda expression results in an undefined behavior once the reference-captured object is accessed.

Example

// $Id: A5-1-4.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <cstdint>

#include <functional>
std::function<std::int32_t()> F()
{
std::int32_t i = 12;
return ([&i]() -> std::int32_t {
i = 100;
return i;
}); // Non-compliant
}
std::function<std::int32_t()> G()
{
std::int32_t i = 12;
return ([i]() mutable -> std::int32_t { return ++i; }); // Compliant
}
void Fn()
{
auto lambda1 = F();
std::int32_t i = lambda1(); // Undefined behavior
auto lambda2 = G();
i = lambda2(); // lambda2() returns 13
}

See also

SEI CERT C++ [10]: EXP61-CPP. A lambda object must not outlive any of its reference captured objects. C++ Core Guidelines [11]: F.53: Avoid capturing by reference in lambdas that will be used nonlocally, including returned, stored on the heap, or passed to another thread.

Rule A5-1-6 (advisory, implementation, automated)

Return type of a non-void return type lambda expression should be explicitly specified.

Rationale

If a non-void return type lambda expression does not specify its return type, then it may be confusing which type it returns. It leads to developers confusion. Note that, while the return type is specified, implicit conversion between type of returned value and return type specified in the lambda expression may occur. This problem should not be ignored.

Example

// $Id: A5-1-6.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <cstdint>
void Fn() noexcept
{

auto lambda1 = []() -> std::uint8_t {
std::uint8_t ret = 0U;
// ...
return ret;
}; // Compliant
auto lambda2 = []() {
// ...
return 0U;
};
// Non-compliant - returned type is not specified
auto x = lambda1(); // Type of x is std::uint8_t
auto y = lambda2(); // What is the type of y?

}

See also

none

Rule A5-1-7 (required, implementation, automated)

A lambda shall not be an operand to decltype or typeid.

Rationale

“The type of the lambda-expression (which is also the type of the closure object) is a unique, unnamed non-union class type [...]” [C++14 Language Standard] [3] Each lambda expression has a different unique underlying type, and therefore the type is not to be used as a decltype or typeid argument. It is allowed to use it as a template parameter and a function argument.

Example

// $Id: A5-1-7.cpp 289815 2017-10-06 11:19:11Z michal.szczepankiewicz $
#include <cstdint>
#include <functional>
#include <vector>
void Fn()
{
auto lambda1 = []() -> std::int8_t { return 1; };
auto lambda2 = []() -> std::int8_t { return 1; };

if (typeid(lambda1) == typeid(lambda2)) // Non-compliant - types of lambda1
// and lambda2 are different
{
// ...
}

std::vector<decltype(lambda1)> v; // Non-compliant
// v.push_back([]() { return 1; }); // Compilation error, type of pushed
// lambda is different than decltype(lambda1)
// using mylambda_t = decltype([](){ return 1; }); // Non-compliant // compilation error

auto lambda3 = []() { return 2; };
using lambda3_t = decltype(lambda3); // Non-compliant - lambda3_t type can
// not be used for lambda expression
// declarations
// lambda3_t lambda4 = []() { return 2; }; // Conversion error at
// compile-time
std::function<std::int32_t()> f1 = []() { return 3; };
std::function<std::int32_t()> f2 = []() { return 3; };

if (typeid(f1) == typeid(f2)) // Compliant - types are equal
{
// ...
}

}

template <typename T>
void Foo(T t);

void Bar()
{
Foo([]() {}); // Compliant
}

See also

none

Rule A5-1-8 (advisory, implementation, automated)

Lambda expressions should not be defined inside another lambda expression.

Rationale

Defining lambda expressions inside other lambda expressions reduces readability of the code.

Example

// $Id: A5-1-8.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <cstdint>
void Fn1()
{
std::int16_t x = 0;
auto f1 = [&x]() {

auto f2 = []() {}; // Non-compliant
f2();

auto f4 = []() {}; // Non-compliant
f4();

}; // Non-compliant

f1();
}
void Fn2()
{
auto f5 = []() {
// Implementation
}; // Compliant
f5();
}

See also

none

Rule A5-1-9 (advisory, implementation, automated)

Identical unnamed lambda expressions shall be replaced with a named function or a named lambda expression.

Rationale

Code duplication reduces readability and maintainability as it might not be obvious that the lambda expressions are identical and any changes need to be applied in more than one place.

Example

// $Id: A5-1-9.cpp 307019 2018-02-09 15:16:47Z christof.meerwald $
#include <algorithm>
#include <cstdint>
#include <vector>

void Fn1(const std::vector<int16_t> &v)
{
// Non-compliant: identical unnamed lambda expression
if (std::none_of(v.begin(), v.end(),
[] (int16_t i) { return i < 0; }))
{
// ...
}
else if (std::all_of(v.begin(), v.end(),
[] (int16_t i) { return i < 0; }))
{
// ...
}
}

void Fn2(const std::vector<int16_t> &v)

{
// Compliant: re-using lambda expression
auto is_negative = [] (int16_t i) { return i < 0; };

if (std::none_of(v.begin(), v.end(), is_negative))
{
// ...
}
else if (std::all_of(v.begin(), v.end(), is_negative))
{
// ...
}

}

See also

C++ Core Guidelines [11]: T.141: Use an unnamed lambda if you need a simple function object in one place only.

Rule M5-2-2 (required, implementation, automated)

A pointer to a virtual base class shall only be cast to a pointer to a derived class by means of dynamic_cast. See MISRA C++ 2008 [7]


## See also
JSF December 2005 [8]: AV Rule 178: Down casting (casting from base to
derived class) shall only be allowed through one of the following mechanism:
Virtual functions that act like dynamic casts (most likely useful in relatively
simple cases); Use of the visitor (or similar) pattern (most likely useful in
complicated cases).

Rule M5-2-3 (advisory, implementation, automated)

Casts from a base class to a derived class should not be performed on polymorphic types. See MISRA C++ 2008 [7] Note: Type is polymorphic if it declares or inherits at least one virtual function.

Rule A5-2-1 (advisory, implementation, automated)

dynamic_cast should not be used.

Rationale

Implementations of dynamic_cast mechanism are unsuitable for use with real-time systems where low memory usage and determined performance are essential. If dynamic casting is essential for your program, usage of its custom implementation should be considered. Also, usage of the dynamic_cast can be replaced with polymorphism, i.e. virtual functions.

Example

// $Id: A5-2-1.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
class A
{
public:
virtual void F() noexcept;
};
class B : public A
{
public:
void F() noexcept override {}
};

void Fn(A* aptr) noexcept

{

// ...

B* bptr = dynamic_cast<B*>(aptr); // Non-compliant

if (bptr != nullptr)
{
// Use B class interface
}
else
{
// Use A class interface
}

}

See also

JSF December 2005 [8]: AV Rule 178: Down casting (casting from base to derived class) shall only be allowed through one of the following mechanism: Virtual functions that act like dynamic casts (most likely useful in relatively simple cases); Use of the visitor (or similar) pattern (most likely useful in complicated cases). C++ Core Guidelines [11]: C.146: Use dynamic_cast where class hierarchy navigation is unavoidable.

Journal of Computing Science and Engineering, Damian Dechev, Rabi Mahapatra, Bjarne Stroustrup: Practical and Verifiable C++ Dynamic Cast for Hard Real-Time Systems. Software-Practice and Experience, Michael Gibbs and Bjarne Stroustrup: Fast dynamic casting.

Rule A5-2-2 (required, implementation, automated)

Traditional C-style casts shall not be used.

Rationale

C-style casts are more dangerous than the C++ named conversion operators. The Cstyle casts are difficult to locate in large programs and the intent of the conversion is not explicit. Traditional C-style casts raise several concerns: C-style casts enable most any type to be converted to most any other type without any indication of the reason for the conversion C-style cast syntax is difficult to identify for both reviewers and tools. Consequently, both the location of conversion expressions as well as the subsequent analysis of the conversion rationale proves difficult for C-style casts Thus, C++ introduces casts (const_cast, dynamic_cast, reinterpret_cast, and static_cast) that address these problems. These casts are not only easy to identify, but they also explicitly communicate the developer’s intent for applying a cast.

Example

// $Id: A5-2-2.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <cstdint>
class C
{
public:
explicit C(std::int32_t) {}
virtual void Fn() noexcept {}
};
class D : public C
{
public:
void Fn() noexcept override {}
};
class E
{
};
std::int32_t G() noexcept
{
return 7;
}

void F() noexcept(false)
{
C a1 = C{10};

// Compliant

C* a2 = (C*)(&a1); // Non-compliant

const C a3(5);

C* a4 = const_cast<C*>(&a3);

E* d1 = reinterpret_cast<E*>(a4); // Compliant - violates another rule

D* d2 = dynamic_cast<D*>(a2);

// Compliant - violates another rule
std::int16_t x1 = 20;
std::int32_t x2 = static_cast<std::int32_t>(x1); // Compliant
std::int32_t x3 = (std::int32_t)x1;
// Non-compliant
std::int32_t x4 = 10;
float
f1 = static_cast<float>(x4);
// Compliant
float
f2 = (float)x4;
// Non-compliant
std::int32_t x5 = static_cast<std::int32_t>(f1); // Compliant
std::int32_t x6 = (std::int32_t)f1;
// Non-compliant
(void)G();
// Non-compliant
static_cast<void>(G());
// Compliant

// Compliant - violates another rule

}

See also

MISRA C++ 2008 [7]: 5-2-4 C-style casts (other than void casts) and functional notation casts (other than explicit constructor calls) shall not be used. JSF December 2005 [8]: AV Rule 185 C++ style casts (const_cast, reinterpret_cast, and static_cast) shall be used instead of the traditional C-style casts.

Rule A5-2-3 (required, implementation, automated)

A cast shall not remove any const or volatile qualification from the type of a pointer or reference.

Rationale

Removal of the const or volatile qualification may not meet developer expectations as it may lead to undefined behavior. Note that either const_cast and traditional C-style casts that remove const or volatile qualification shall not be used.

Example

// $Id: A5-2-3.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <cstdint>

void F1(const char* str) noexcept(false)

{

*(const_cast<char*>(str)) =

’\0’; // Non-compliant - const qualification removed

}

class C
{
public:
explicit C(std::int32_t) {}
};
void F2() noexcept(false)
{
C const a1 = C(10);
C* a2 = const_cast<C*>(&a1); // Non-compliant - const qualification removed

// Non-compliant - const qualification removed

C* a3 = (C*)&a1;

}

extern volatile std::int32_t* F3() noexcept;

void F4() noexcept
{

volatile std::int32_t* ptr1 = F3();

// ...

std::int32_t* ptr2 = const_cast<std::int32_t*>(

ptr1); // Non-compliant - volatile qualification removed

// ...

std::int32_t* ptr3 =
(std::int32_t*)ptr1; // Non-compliant - volatile qualification removed

}

See also

MISRA C++ 2008 [7]: 5-2-5 A cast shall not remove any const or volatile qualification from the type of a pointer or reference.

Rule M5-2-6 (required, implementation, automated)

A cast shall not convert a pointer to a function to any other pointer type, including a pointer to function type. See MISRA C++ 2008 [7]

Rule A5-2-4 (required, implementation, automated)

reinterpret_cast shall not be used.

Rationale

Use of reinterpret_cast may violate type safety and cause the program to access a variable as if it were of another, unrelated type.

Example

// $Id: A5-2-4.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <cstdint>
#include <string>
void F1() noexcept

{
std::string str = "Hello";

std::int32_t* ptr = reinterpret_cast<std::int32_t*>(&str); // Non-compliant

}
struct A
{
std::int32_t x;
std::int32_t y;
};
class B
{
public:
virtual ~B() {}

private:
std::int32_t x;

};
class C : public B
{
};
class D : public B
{
};

void F2(A* ptr) noexcept

{

B* b1 = reinterpret_cast<B*>(ptr); // Non-compliant

std::int32_t num = 0;

A* a1 = reinterpret_cast<A*>(num); // Non-compliant

A* a2 = (A*)

num; // Compliant with this rule, but non-compliant with Rule A5-2-2.

B* b2 = reinterpret_cast<B*>(num); // Non-compliant

D d;

C* c1 = reinterpret_cast<C*>(&d); // Non-compliant - cross cast

C* c2 = (C*)&d; // Compliant with this rule, but non-compliant with Rule

// A5-2-2. Cross-cast.

}

B* b3 = &d;

// Compliant - class D

is a subclass of class B

See also

MISRA C++ 2008 [7]: Rule 5-2-7 An object with pointer type shall not be converted to an unrelated pointer type, either directly or indirectly. C++ Core Guidelines [11]: Type.1: Don’t use reinterpret_cast.

Rule A5-2-6 (required, implementation, automated)

The operands of a logical && or \ shall be parenthesized if the operands contain binary operators.

Rationale

Parentheses are required to add clarity in logical expressions making code easier to review versus code based only C++ operator precedence rules.

Example

// $Id: A5-2-6.cpp$

#include <cstdint>

void Fn(std::int32_t value) noexcept
{
if (value > 0 && value < 3) // Non-compliant
{
// do some work
}
else if ((value > 1) && (value < 2)) // Compliant
{
// do some work
}
else
{
// do some work
}

return;

}

See also

MISRA C++ 2008 [7]: M5-2-1: Each operand of a logical && or || shall be a postfix expression. JSF December 2005 [8]: AV Rule 158: The operands of a logical && or \ shall be parenthesized if the operands contain binary operators. C++ Core Guidelines [11]: ES.41: If in doubt about operator precedence, parenthesize

Rule M5-2-8 (required, implementation, automated)

An object with integer type or pointer to void type shall not be converted to an object with pointer type. See MISRA C++ 2008 [7]

Rule M5-2-9 (required, implementation, automated)

A cast shall not convert a pointer type to an integral type.

See MISRA C++ 2008 [7] Note: Obligation level changed.

Rule M5-2-10 (required, implementation, automated)

The increment (++) and decrement ( ) operators shall not be mixed with other operators in an expression. See MISRA C++ 2008 [7] Note: Obligation level changed.

Rule M5-2-11 (required, implementation, automated)

The comma operator, && operator and the || operator shall not be overloaded. See MISRA C++ 2008 [7]

Rule A5-2-5 (required, implementation, automated)

An array or container shall not be accessed beyond its range.

Rationale

To avoid undefined behavior, range checks should be coded to ensure that container access via iterator arithmetic or subscript operator is within defined bounds. This could also be achieved by accessing an array via a subscript operator with constant indices only. When copying data via standard library algorithms (such as std::copy or std::transform), the target destination must be guaranteed to be large enough to hold the data. Note: This rule applies to C-style arrays and all other containers (including std::basic_string) that access their elements via iterators or via an index. The term iterator includes pointers. Note: Calculating an iterator one past the last element of the array is well defined, but dereferencing such an iterator is not.

Example

// $Id: A5-2-5.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <array>
#include <cstdint>
#include <iostream>
void Fn1() noexcept
{

constexpr std::int32_t arraySize = 16;
std::int32_t array[arraySize]{0};

std::int32_t elem1 =
array[0]; // Compliant - access with constant literal that
// is less than ArraySize
std::int32_t elem2 =
array[12]; // Compliant - access with constant literal that
// is less than ArraySize
for (std::int32_t idx = 0; idx < 20; ++idx)
{
std::int32_t elem3 =
array[idx]; // Non-compliant
- access beyond
// bounds, which
has 16 elements
}

ArraySize

std::int32_t shift = 25;
std::int32_t elem4 =

*(array + shift); // Non-compliant - access beyond ArraySize bounds

std::int32_t index = 0;
std::cin >> index;
std::int32_t elem5 =
array[index]; // Non-compliant - index may exceed the ArraySize bounds
if (index < arraySize)
{
std::int32_t elem6 = array[index]; // Compliant - range check coded
}
}
void Fn2() noexcept
{
constexpr std::int32_t arraySize = 32;
std::array<std::int32_t, arraySize> array;
array.fill(0);

std::int32_t elem1 =
array[10]; // Compliant - access with constant literal that
// is less than ArraySize
std::int32_t index = 40;
std::int32_t elem2 =
array[index]; // Non-compliant - access beyond ArraySize bounds
try
{
std::int32_t elem3 =
array.at(50); // Compliant - at() method provides a
// range check, throwing an
exception if
// input exceeds the bounds
}
catch (std::out_of_range&)
{
// Handle an error

}

for (auto&& e : array) // The std::array provides a possibility to iterate
// over its elements with range-based loop
{
// Iterate over all elements
}

}

See also

HIC++ v4.0 [9]: 5.2.1: Ensure that pointer or array access is demonstrably within bounds of a valid object.

Rule M5-2-12 (required, implementation, automated)

An identifier with array type passed as a function argument shall not decay to a pointer. See MISRA C++ 2008 [7]


## See also
C++ Core Guidelines [11]: C.152: Never assign a pointer to an array of derived
class objects to a pointer to its base.
C++ Core Guidelines [11]: R.2: In interfaces, use raw pointers to denote
individual objects (only).
C++ Core Guidelines [11]: I.13: Do not pass an array as a single pointer.

Rule M5-3-1 (required, implementation, automated)

Each operand of the ! operator, the logical && or the logical || operators shall have type bool. See MISRA C++ 2008 [7]

Rule M5-3-2 (required, implementation, automated)

The unary minus operator shall not be applied to an expression whose underlying type is unsigned. See MISRA C++ 2008 [7]

Rule M5-3-3 (required, implementation, automated)

The unary & operator shall not be overloaded. See MISRA C++ 2008 [7]

Rule M5-3-4 (required, implementation, automated)

Evaluation of the operand to the sizeof operator shall not contain side effects. See MISRA C++ 2008 [7]

Rule A5-3-1 (required, implementation, non-automated)

Evaluation of the operand to the typeid operator shall not contain side effects.

Rationale

The operand of typeid operator is evaluated only if it is a function call which returns a reference to a polymorphic type. Providing side effects to typeid operator, which takes place only under special circumstances, makes the code more difficult to maintain.

Example

// $Id: A5-3-1.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <typeinfo>
bool SideEffects() noexcept
{
// Implementation
return true;
}
class A
{
public:
static A& F1() noexcept { return a; }
virtual ~A() {}

private:
static A a;
};
A A::a;
void F2() noexcept(false)
{
typeid(SideEffects()); // Non-compliant - sideEffects() function not called
typeid(A::F1()); // Non-compliant - A::f1() functions called to determine
// the polymorphic type
}

See also

HIC++ v4.0 [9]: 5.1.6 Do not code side effects into the right-hand operands of: &&, ||, sizeof, typeid or a function passed to condition_variable::wait.

Rule A5-3-2 (required, implementation, partially automated)

Null pointers shall not be dereferenced.

Rationale

Dereferencing a NULL pointer leads to undefined behavior. Note: It is required requires that a pointer is checked for non-NULL status before dereferencing occurs.

Example

// $Id: A5-3-2.cpp 305629 2018-01-29 13:29:25Z piotr.serwa $
#include <iostream>
#include <memory>
#include <cstdint>

class A
{
public:
A(std::uint32_t a) : a(a) {}
std::uint32_t GetA() const noexcept { return a; }

private:
std::uint32_t a;
};

bool Sum(const A* lhs, const A* rhs)

{
//non-compliant, not checking if pointer is invalid
return lhs->GetA() + rhs->GetA();

}

int main(void)
{
auto l = std::make_shared<A>(3);
decltype(l) r;

auto sum = Sum(l.get(), r.get());

std::cout << sum << std::endl;
return 0;

}

See also

JSF December 2005 [8]: AV Rule 174: The null pointer shall not be dereferenced. SEI CERT C++ Coding Standard [10]: EXP34-C: Do not dereference null pointers. C++ Core Guidelines [11]: ES.65: Don’t dereference an invalid pointer.

Rule A5-3-3 (required, implementation, automated)

Pointers to incomplete class types shall not be deleted.

Rationale

Incomplete class types are forward declared class types, for which the compiler has not yet seen a definition. It is undefined behavior if a pointer to an incomplete class type is deleted, and the class has a non-trivial destructor or a deallocation function. This rule prohibits deletion of such a pointer even in the harmless case of a trivially destructible class type without a deallocation function, since a non-trivial destructor or a deallocation function may be added later as the code evolves.

Example

// $Id: A5-3-3.cpp 309184 2018-02-26 20:38:28Z jan.babst $

// Non-compliant: At the point of deletion, pimpl points
// to an incomplete class type.
class Bad
{
class Impl;
Impl* pimpl;

public:
// ...
~Bad() { delete pimpl; } // violates A18-5-2

};

// Compliant: At the point of deletion, pimpl points to
// a complete class type.

// In a header file ...
class Good
{
class Impl;
Impl* pimpl;

public:
// ...
~Good();

};

// In an implementation file ...
class Good::Impl
{
// ...
};
// Good::Impl is a complete type now

Good::~Good()
{
delete pimpl; // violates A18-5-2
}

// Compliant: Contemporary solution using std::unique_ptr
// and conforming to A18-5-2.
// Note that std::unique_ptr<Impl> requires Impl to be a complete type
// at the point where pimpl is deleted and thus automatically enforces
// A5-3-3. This is the reason why the destructor of Better must be defined in an
// implementation file when Better::Impl is a complete type, even if the
// definition is just the default one.

// In a header file ...
#include <memory>
class Better
{
class Impl;
std::unique_ptr<Impl> pimpl;

public:
// ...
~Better();

};

// In an implementation file ...
class Better::Impl
{
// ...
};
// Better::Impl is a complete type now

Better::~Better() = default;

See also

ISO/IEC 14882:2014 [3]: 5.3.5: [expr.delete] SEI CERT C++ Coding Standard [10]: EXP57-CPP: Do not cast or delete pointers to incomplete classes.

Rule A5-5-1 (required, implementation, automated)

A pointer to member shall not access non-existent class members.

Rationale

Usage of a pointer-to-member expression leads to undefined behavior in the following cases: The pointer to member is a null pointer. The dynamic type of the object does not contain the member to which the called pointer to member refers.

Example

// $Id: A5-5-1.cpp 302200 2017-12-20 17:17:08Z michal.szczepankiewicz $

class A
{
public:
virtual ~A() = default;
};

class AA : public A
{
public:
virtual ~AA() = default;
virtual void foo() { }

using ptr = void (AA::*)();

};

class B
{
public:
static AA::ptr foo_ptr2;
};

AA::ptr B::foo_ptr2;

int main(void)
{

A* a = new A();

void (A::*foo_ptr1)() = static_cast<void(A::*)()>(&AA::foo);

(a->*foo_ptr1)(); // non-compliant

delete a;

AA* aa = new AA();

(aa->*B::foo_ptr2)(); // non-compliant, not explicitly initialized

delete aa;

return 0;

}

See also

SEI CERT C++ Coding Standard [10]: OOP55-CPP: Do not use pointer-tomember operators to access nonexistent members

Rule A5-6-1 (required, implementation, automated)

The right hand operand of the integer division or remainder operators shall not be equal to zero.

Rationale

The result is undefined if the right hand operand of the integer division or the remainder operator is zero.

Example

// $Id: A5-6-1.cpp 305629 2018-01-29 13:29:25Z piotr.serwa $
#include <cstdint>
#include <stdexcept>
std::int32_t Division1(std::int32_t a, std::int32_t b) noexcept
{
return (a / b); // Non-compliant - value of b could be zero
}
std::int32_t Division2(std::int32_t a, std::int32_t b)
{
if (b == 0)
{
throw std::runtime_error("Division by zero error");
}
return (a / b); // Compliant - value of b checked before division
}
double Fn()
{
std::int32_t x = 20 / 0; // Non-compliant - undefined behavior
x = Division1(20, 0);
// Undefined behavior
x = Division2(20,
0); // Preconditions check will throw a runtime_error from
// division2() function
std::int32_t remainder = 20 % 0; // Non-compliant - undefined behavior
}

See also

HIC++ v4.0 [9]: 5.5.1 Ensure that the right hand operand of the division or remainder operators is demonstrably non-zero.

C++ Core Guidelines [11]: ES.105: Don’t divide by zero.

Rule M5-8-1 (required, implementation, partially automated)

The right hand operand of a shift operator shall lie between zero and one less than the width in bits of the underlying type of the left hand operand. See MISRA C++ 2008 [7]

Rule A5-10-1 (required, implementation, automated)

A pointer to member virtual function shall only be tested for equality with null-pointer-constant.

Rationale

The result of equality comparison between pointer to member virtual function and anything other than null-pointer-constant (i.e. nullptr, see: A4-10-1) is unspecified.

Example

// $Id: A5-10-1.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
class A
{
public:
virtual ~A() = default;
void F1() noexcept {}
void F2() noexcept {}
virtual void F3() noexcept {}
};

void Fn()
{
bool b1 = (&A::F1 == &A::F2);
// Compliant
bool b2 = (&A::F1 == nullptr); // Compliant
bool b3 = (&A::F3 == nullptr); // Compliant
bool b4 = (&A::F3 != nullptr); // Compliant
bool b5 = (&A::F3 == &A::F1);
// Non-compliant
}

See also

HIC++ v4.0 [9]: 5.7.2 Ensure that a pointer to member that is a virtual function is only compared (==) with nullptr.

JSF December 2005 [8]: AV Rule 97.1 Neither operand of an equality operator (== or !=) shall be a pointer to a virtual member function.

Rule M5-14-1 (required, implementation, automated)

The right hand operand of a logical &&, || operators shall not contain side effects. See MISRA C++ 2008 [7]

Rule A5-16-1 (required, implementation, automated)

The ternary conditional operator shall not be used as a sub-expression.

Rationale

Using the result of the ternary conditional operator as an operand or nesting conditional operators makes the code less readable and more difficult to maintain.

Example

// $Id: A5-16-1.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <cstdint>
constexpr bool Fn1(std::int32_t x)
{
return (x > 0); // Compliant
}
std::int32_t Fn2(std::int32_t x)
{
std::int32_t i = (x >= 0 ? x : 0); // Compliant

std::int32_t j =
x + (i == 0 ? (x >= 0 ? x : -x) : i); // Non-compliant - nested
// conditional
operator
// and used as
a
// sub-expression
return (
i>0
? (j > 0 ? i + j : i)
: (j > 0 ? j : 0)); // Non-compliant - nested conditional operator

}

See also

HIC++ v4.0 [9]: 5.8.1 Do not use the conditional operator (?:) as a subexpression.

Rule M5-17-1 (required, implementation, non-automated)

The semantic equivalence between a binary operator and its assignment operator form shall be preserved. See MISRA C++ 2008 [7]

Rule M5-18-1 (required, implementation, automated)

The comma operator shall not be used. See MISRA C++ 2008 [7]

Rule M5-19-1 (required, implementation, automated)

Evaluation of constant unsigned integer expressions shall not lead to wrap-around. See MISRA C++ 2008 [7] Note: Obligation level changed Note: This rule applies to bit-fields, too.

Rule M6-2-1 (required, implementation, automated)

Assignment operators shall not be used in sub-expressions.

See MISRA C++ 2008 [7]

Exception

It is allowed that a condition of the form type-specifier-seq declarator uses an assignment operator. This exception is introduced because alternative mechanisms for achieving the same effect are cumbersome and error-prone.

Rule A6-2-1 (required, implementation, automated)

Move and copy assignment operators shall either move or respectively copy base classes and data members of a class, without any side effects.

Rationale

It is expected behavior that the move/copy assigned operator are only used to move/copy the object of the class type and possibly set moved-from object to a valid state. Those operators are not supposed to provide any performance overhead or side effects that could affect moving or copying the object. Note: Class members that are not essential for a class invariant may not need to be moved/copied (e.g. caches, debug information).

Example

// $Id: A6-2-1.cpp 305786 2018-01-30 08:58:33Z michal.szczepankiewicz $

#include <cstdint>
#include <utility>
class A
{
public:
A& operator=(const A& oth) // Compliant
{
if(&oth == this)
{
return *this;

}
x = oth.x;

return *this;

}

private:
std::int32_t x;
};
class B
{
public:
~B() { delete ptr; }

//compliant
B& operator=(B&& oth)
{

if(&oth == this)
{

return *this;

}
ptr = std::move(oth.ptr);
// Compliant - this is not a side-effect, in this
// case it is essential to leave moved-from object
// in a valid state, otherwise double deletion will
// occur.

return *this;

}

private:
std::int32_t* ptr;

};

class C
{
public:
C& operator=(const C& oth)
{
if(&oth == this)
{
return *this;

}
x = oth.x % 2; // Non-compliant - unrelated side-effect

return *this;

}

private:
std::int32_t x;
};

class D
{
public:
explicit D(std::uint32_t a) : a(a), noOfModifications(0) {}

D& operator=(const D& oth)
{
if(&oth == this)
{
return *this;

}
a = oth.a;
//compliant, not copying the debug information about number of modifications

return *this;

}

void SetA(std::uint32_t aa)

{
++noOfModifications;
a = aa;
}
std::uint32_t GetA() const noexcept
{
return a;
}

private:
std::uint32_t a;
std::uint64_t noOfModifications;
};

See also

JSF December 2005 [8]: AV Rule 83: An assignment operator shall assign all data members and bases that affect the class invariant (a data element representing a cache, for example, would not need to be copied).

Rule A6-2-2 (required, implementation, automated)

Expression statements shall not be explicit calls to constructors of temporary objects only.

Rationale

The developer’s intention might have been to define an unnamed local variable that would live until the end of the scope to implement the RAII pattern (Resource Acquisition Is Initialization). But as there are no unnamed variables in C++, it is in fact only creating a temporary object that gets destroyed again at the end of the full expression.

Example

// $Id: A6-2-2.cpp 326655 2018-07-20 14:58:55Z christof.meerwald $

#include <cstdint>
#include <fstream>
#include <mutex>

class A
{
public:
void SetValue1(std::int32_t value)
{
std::lock_guard<std::mutex> {m_mtx}; // Non-compliant: temporary object
// Assignment to m_value is not protected by lock
m_value = value;
}

void SetValue2(std::int32_t value)
{
std::lock_guard<std::mutex> guard{m_mtx}; // Compliant: local variable m_value = value;

}

private:
mutable std::mutex m_mtx;
std::int32_t m_value;
};

void Print(std::string const & fname, std::string const & s)
{
// Compliant: Not only constructing a temporary object
std::ofstream{fname}.write(s.c_str(), s.length());
}

See also

C++ Core Guidelines [11]: ES.84: Don’t (try to) declare a local variable with no name C++ Core Guidelines [11]: CP.44: Remember to name your lock_guards and unique_locks Rule M6-2-2 (required, implementation, partially automated) Floatingpoint expressions shall not be directly or indirectly tested for equality or inequality. See MISRA C++ 2008 [7]

Rule M6-2-3 (required, implementation, automated)

Before preprocessing, a null statement shall only occur on a line by itself; it may be followed by a comment, provided that the first character following the null statement is a white-space character. See MISRA C++ 2008 [7]

Rule M6-3-1 (required, implementation, automated)

The statement forming the body of a switch, while, do ... while or for statement shall be a compound statement. See MISRA C++ 2008 [7]

Rule M6-4-1 (required, implementation, automated)

An if ( condition ) construct shall be followed by a compound statement. The else keyword shall be followed by either a compound statement, or another if statement. See MISRA C++ 2008 [7]

Rule M6-4-2 (required, implementation, automated)

All if ... else if constructs shall be terminated with an else clause. See MISRA C++ 2008 [7]

Rule M6-4-3 (required, implementation, automated)

A switch statement shall be a well-formed switch statement. See MISRA C++ 2008 [7]

Rule M6-4-4 (required, implementation, automated)

A switch-label shall only be used when the most closelyenclosing compound statement is the body of a switch statement. See MISRA C++ 2008 [7]

Rule M6-4-5 (required, implementation, automated)

An unconditional throw or break statement shall terminate every nonempty switch-clause. See MISRA C++ 2008 [7]

Rule M6-4-6 (required, implementation, automated)

The final clause of a switch statement shall be the default-clause. See MISRA C++ 2008 [7]

Rule M6-4-7 (required, implementation, automated)

The condition of a switch statement shall not have bool type. See MISRA C++ 2008 [7] Note: "‘The condition shall be of integral type, enumeration type, or class type. If of class type, the condition is contextually implicitly converted (Clause 4) to an integral or enumeration type."’ [C++14 Language Standard, 6.4.2 The switch statement]

Rule A6-4-1 (required, implementation, automated)

A switch statement shall have at least two case-clauses, distinct from the default label.

Rationale

A switch statement constructed with less than two case-clauses can be expressed as an if statement more naturally. Note that a switch statement with no case-clauses is redundant.

Example

// $Id: A6-4-1.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <cstdint>
void F1(std::uint8_t choice) noexcept
{
switch (choice)
{
default:
break;
} // Non-compliant, the switch statement is redundant
}
void F2(std::uint8_t choice) noexcept
{
switch (choice)
{
case 0:
// ...
break;

default:
// ...
break;
} // Non-compliant, only 1 case-clause

if (choice == 0) // Compliant, an equivalent if statement
{
// ...
}
else

{

// ...

}

// ...
switch (choice)
{
case 0:
// ...
break;

case 1:
// ...
break;

default:
// ...
break;
} // Compliant

}

See also

MISRA C++ 2008 [7]: Rule 6-4-8 Every switch statement shall have at least one case-clause. HIC++ v4.0 [9]: 6.1.4 Ensure that a switch statement has at least two case labels, distinct from the default label.

Rule A6-5-1 (required, implementation, automated)

A for-loop that loops through all elements of the container and does not use its loop-counter shall not be used.

Rationale

A for-loop that simply loops through all elements of the container and does not use its loop-counter is equivalent to a range-based for statement that reduces the amount of code to maintain correct loop semantics.

Example

// $Id: A6-5-1.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <cstdint>
#include <iterator>
void Fn() noexcept
{
constexpr std::int8_t arraySize = 7;

std::uint32_t array[arraySize] = {0, 1, 2, 3, 4, 5, 6};

for (std::int8_t idx = 0; idx < arraySize; ++idx) // Compliant
{
array[idx] = idx;
}

for (std::int8_t idx = 0; idx < arraySize / 2;
++idx) // Compliant - for does not loop though all elements
{
// ...
}

for (std::uint32_t* iter = std::begin(array); iter != std::end(array);

++iter) // Non-compliant

{

// ...

}

for (std::int8_t idx = 0; idx < arraySize; ++idx) // Non-compliant
{
// ...
}

for (std::uint32_t value :
array) // Compliant - equivalent to non-compliant loops above
{
// ...
}

for (std::int8_t idx = 0; idx < arraySize; ++idx) // Compliant
{
if ((idx % 2) == 0)
{
// ...
}
}

}

See also

HIC++ v4.0 [9]: 6.2.1 Implement a loop that only uses element values as a range-based loop. C++ Core Guidelines [11]: ES.55: Avoid the need for range checking. C++ Core Guidelines [11]: ES.71: Prefer a range-for-statement to a forstatement when there is a choice.

Rule A6-5-2 (required, implementation, automated)

A for loop shall contain a single loop-counter which shall not have floating-point type.

Rationale

A for loop without a loop-counter is simply a while loop. If this is the desired behavior, then a while loop is more appropriate. Floating types, as they should not be tested for equality/inequality, are not to be used as loop-counters.

Example

// $Id: A6-5-2.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <cstdint>
namespace
{
constexpr std::int32_t xlimit = 20;
constexpr std::int32_t ylimit = 15;
constexpr float zlimit = 2.5F;
constexpr std::int32_t ilimit = 100;
}
void Fn() noexcept
{
std::int32_t y = 0;

for (std::int32_t x = 0; x < xlimit && y < ylimit;
x++, y++) // Non-compliant, two loop-counters
{
// ...
}

for (float z = 0.0F; z != zlimit;
z += 0.1F) // Non-compliant, float with !=
{
// ...
}

for (float z = 0.0F; z < zlimit; z += 0.1F) // Non-compliant, float with <
{
// ...
}

for (std::int32_t i = 0; i < ilimit; ++i) // Compliant
{
// ...
}

}

See also

MISRA C++ 2008 [7]: Rule 6-5-1 A for loop shall contain a single loop-counter which shall not have floating type. C++ Core Guidelines [11]: ES.72: Prefer a for-statement to a while-statement when there is an obvious loop variable.

Rule M6-5-2 (required, implementation, automated)

If loop-counter is not modified by or ++, then, within condition, the loop-counter shall only be used as an operand to <=, <, > or >=. See MISRA C++ 2008 [7]

Rule M6-5-3 (required, implementation, automated)

The loop-counter shall not be modified within condition or statement. See MISRA C++ 2008 [7]

Rule M6-5-4 (required, implementation, automated)

The loop-counter shall be modified by one of: , ++, = n, or + = n; where n remains constant for the duration of the loop.

See MISRA C++ 2008 [7]

Note: “n remains constant for the duration of the loop” means that “n” can be either a literal, a constant or constexpr value.

Rule M6-5-5 (required, implementation, automated)

A loop-control-variable other than the loop-counter shall not be modified within condition or expression. See MISRA C++ 2008 [7]

Rule M6-5-6 (required, implementation, automated)

A loop-control-variable other than the loop-counter which is modified in statement shall have type bool. See MISRA C++ 2008 [7]

Rule A6-5-3 (advisory, implementation, automated)

Do statements should not be used.

Rationale

Do-statements are bug-prone, as the termination condition is checked at the end and can be overlooked.

Exception

A do-statement may be used in a function-like macro to ensure that its invocation behaves like an expression statement consisting of a function call (see http://cfaq.com/cpp/multistmt.html). Note: Rule A16-0-1 forbids function-like macros. This exception is kept in case rule A16-0-1 is disabled in a project.

Example

// $Id: A6-5-3.cpp 291350 2017-10-17 14:31:34Z jan.babst $

#include <cstdint>

// Compliant by exception
#define SWAP(a, b)         \
do                         \
{                          \
    decltype(a) tmp = (a); \
    (a) = (b);             \
    (b) = tmp;             \
} while (0)

// Non-compliant
#define SWAP2(a, b)    \
decltype(a) tmp = (a); \
(a) = (b);             \
(b) = tmp;             \

int main(void)
{
    uint8_t a = 24;
    uint8_t b = 12;

    if (a > 12)
        SWAP(a, b);

    // if (a > 12)
    //SWAP2(a, b);
    // Does not compile, because only the first line is used in the body of the
    // if-statement. In other cases this may even cause a run-time error.
    // The expansion contain two semicolons in a row, which may be flagged by
    // compiler warnings.

    // Expands to:
    // if (a > 12)
    //decltype(a) tmp = (a);
    // (a) = (b);
    // (b) = tmp;;

    return 0;
}

See also

C++ Core Guidelines [11]: ES.75: Avoid do-statements.

Rule A6-5-4 (advisory, implementation, automated)

For-init-statement and expression should not perform actions other than loop-counter initialization and modification.

Rationale

If only a loop-counter is used in the for-init-statement and expression, it increases readability and it is easier to understand and maintain code.

Example

// $Id: A6-5-4.cpp 305629 2018-01-29 13:29:25Z piotr.serwa $
#include <cstdint>

void Fn() noexcept
{
    for (std::int32_t x = 0, MAX = 10; x < MAX; x++) // compliant with A6-5-2, but
                                                     // non-compliant with advisory A6-5-4
    {
        // ...
    }
}

See also

JSF December 2005 [8]: AV Rule 198: The initialization expression in a for loop will perform no actions other than to initialize the value of a single for loop parameter.

JSF December 2005 [8]: AV Rule 199: The increment expression in a for loop will perform no action other than to change a single loop parameter to the next value for the loop.

Rule A6-6-1 (required, implementation, automated)

The goto statement shall not be used.

Rationale

Using goto statement significantly complicates the logic, makes the code difficult to read and maintain, and may lead to incorrect resources releases or memory leaks.

Example

// $Id: A6-6-1.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <cstdint>
namespace
{
constexpr std::int32_t loopLimit = 100;
}
void F1(std::int32_t n) noexcept
{
if (n < 0)
{
// goto exit; // Non-compliant - jumping to exit from here crosses ptr
// pointer initialization, compilation
// error
}

std::int32_t* ptr = new std::int32_t(n);

// ...
exit:
delete ptr;
}
void F2() noexcept
{
// ...
goto error; // Non-compliant
// ...
error:; // Error handling and cleanup
}
void F3() noexcept
{
for (std::int32_t i = 0; i < loopLimit; ++i)
{
for (std::int32_t j = 0; j < loopLimit; ++j)
{
for (std::int32_t k = 0; k < loopLimit; ++k)
{
if ((i == j) && (j == k))
{
// ...
goto loop_break; // Non-compliant
}
}

}

}

loop_break:;
}

// ...

See also

JSF December 2005 [8]: AV Rule 189 The goto statement shall not be used. C++ Core Guidelines [11]: ES.76: Avoid goto. C++ Core Guidelines [11]: NR.6: Don’t: Place all cleanup actions at the end of a function and goto exit.

Rule M6-6-1 (required, implementation, automated)

Any label referenced by a goto statement shall be declared in the same block, or in a block enclosing the goto statement. See MISRA C++ 2008 [7]

Rule M6-6-2 (required, implementation, automated)

The goto statement shall jump to a label declared later in the same function body. See MISRA C++ 2008 [7]

Rule M6-6-3 (required, implementation, automated)

The continue statement shall only be used within a well-formed for loop. See MISRA C++ 2008 [7]

Rule A7-1-1 (required, implementation, automated)

Constexpr or const specifiers shall be used for immutable data declaration.

Rationale

If data is declared to be const or constexpr then its value can not be changed by mistake. Also, such declaration can offer the compiler optimization opportunities.

Note that the constexpr specifier in an object declaration implies const as well.

Example

//% $Id: A7-1-1.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <cstdint>
#include <limits>
void Fn()
{
const std::int16_t x1 = 5;
// Compliant
constexpr std::int16_t x2 = 5; // Compliant
std::int16_t x3 =
5; // Non-compliant - x3 is not modified but not declared as
// constant (const or constexpr)
}

See also

C++ Core Guidelines [11]: ES.25: Declare objects const or constexpr unless you want to modify its value later on. C++ Core Guidelines [11]: Con.1: By default, make objects immutable. C++ Core Guidelines [11]: Con.4: Use const to define objects with values that do not change after construction.

Rule A7-1-2 (required, implementation, automated)

The constexpr specifier shall be used for values that can be determined at compile time.

Rationale

The constexpr specifier declares that it is possible to evaluate the value of the function or variable at compile time, e.g. integral type overflow/underflow, configuration options or some physical constants. The compile-time evaluation can have no side effects so it is more reliable than const expressions. Note that the constexpr specifier in an object declaration implies const, and when used in a function declaration it implies inline. Note also that since 2014 C++ Language Standard constexpr specifier in member function declaration no longer implicitly implies that the member function is const.

Example

//% $Id: A7-1-2.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <cstdint>
std::int32_t Pow1(std::int32_t number)
{
return (number * number);

}

constexpr std::int32_t Pow2(
std::int32_t number) // Possible compile-time computing
// because of constexpr specifier
{
return (number * number);

}
void Fn()
{
constexpr std::int16_t i1 = 20; // Compliant, evaluated at compile-time
const std::int16_t i2 = 20; // Non-compliant, possible run-time evaluation
std::int32_t twoSquare =
Pow1(2); // Non-compliant, possible run-time evaluation
const std::int32_t threeSquare =
Pow1(3); // Non-compliant, possible run-time evaluation
// static_assert(threeSquare == 9, "pow1(3) did not succeed."); // Value
// can not be static_assert-ed
constexpr std::int32_t fiveSquare =
Pow2(5); // Compliant, evaluated at compile time
static_assert(fiveSquare == 25,
"pow2(5) did not succeed."); // Compliant, constexpr
// evaluated at compile
// constexpr std::int32_t int32Max =
// std::numeric_limits<std::int32_t>::max() + 1; //
// Compliant - compilation error due to
// compile-time evaluation (integer overflow)
}
class A
{
public:
static constexpr double pi = 3.14159265; // Compliant - value of PI can be
// determined in compile time

time

// constexpr double e = 2.71828182; // Non-compliant - constexprs need
// to be static members, compilation error

constexpr A() = default; // Compliant

};

See also

C++ Core Guidelines [11]: Con.5: Use constexpr for values that can be computed at compile time.

Rule M7-1-2 (required, implementation, automated)

A pointer or reference parameter in a function shall be declared as pointer to const or reference to const if the corresponding object is not modified. See MISRA C++ 2008 [7]


## See also

C++ Core Guidelines [11]: Con.3: By default, pass pointers and references to
consts.
Rule A7-1-3 (required, implementation, automated) CV-qualifiers shall
be placed on the right hand side of the type that is a typedef or a
using name.
## Rationale
If the type is a typedef or a using name, placing const or volatile qualifier on the left
hand side may result in confusion over what part of the type the qualification applies
to.
## Example

```cpp
// $Id: A7-1-3.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <cstdint>

using IntPtr = std::int32_t*;

using IntConstPtr = std::int32_t* const;

using ConstIntPtr = const std::int32_t*;

void Fn(const std::uint8_t& input) // Compliant
{
std::int32_t value1 = 10;
std::int32_t value2 = 20;

const IntPtr ptr1 =

&value1; // Non-compliant - deduced type is std::int32_t*

// const, not const std::int32_t*

// ptr1 = &value2; // Compilation error, ptr1 is read-only variable

IntPtr const ptr2 =

&value1; // Compliant - deduced type is std::int32_t* const

// ptr2 = &value2; // Compilation error, ptr2 is read-only variable

IntConstPtr ptr3 = &value1; // Compliant - type is std::int32_t* const, no

// additional qualifiers needed

// ptr3 = &value2; // Compilation error, ptr3 is read-only variable

ConstIntPtr ptr4 = &value1; // Compliant - type is const std::int32_t*

const ConstIntPtr ptr5 = &value1; // Non-compliant, type is const

// std::int32_t*

ConstIntPtr const ptr6 =

// std::int32_t*

&value1; // Compliant - type is const std::int32_t* const

const, not const const

}

See also

HIC++ v4.0 [9]: 7.1.4 Place CV-qualifiers on the right hand side of the type they apply to

Rule A7-1-4 (required, implementation, automated)

The register keyword shall not be used.

Rationale

This feature was deprecated in the 2011 C++ Language Standard [2] and may be withdrawn in a later version. Moreover, most compilers ignore register specifier and perform their own register assignments.

Example

// $Id: A7-1-4.cpp 289448 2017-10-04 11:11:03Z michal.szczepankiewicz $
#include <cstdint>
std::int32_t F1(register std::int16_t number) noexcept // Non-compliant
{
return ((number * number) + number);

}
void F2(std::int16_t number) noexcept // Compliant
{
register std::int8_t x = 10;
// Non-compliant
std::int32_t result = F1(number); // Compliant
// ...
}

See also

JSF December 2005 [8]: AV Rule 140 The register storage class specifier shall not be used. HIC++ v4.0 [9]: 1.3.2 Do not use the register keyword

Rule A7-1-5 (required, implementation, automated)

The auto specifier shall not be used apart from following cases: (1) to declare that a variable has the same type as return type of a function call, (2) to declare that a variable has the same type as initializer of non-fundamental type, (3) to declare parameters of a generic lambda expression, (4) to declare a function template using trailing return type syntax.

Rationale

Using the auto specifier may lead to unexpected type deduction results, and therefore to developers confusion. In most cases using the auto specifier makes the code less readable. Note that it is allowed to use the auto specifier in following cases:

  1. When declaring a variable that is initialized with a function call or initializer of non-fundamental type. Using the auto specifier for implicit type deduction in such cases will ensure that no unexpected implicit conversions will occur. In such case, explicit type declaration would not aid readability of the code.
  2. When declaring a generic lambda expression with auto parameters
  3. When declaring a function template using trailing return type syntax

Example

// $Id: A7-1-5.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <cstdint>
#include <vector>

class A
{
};
void F1() noexcept
{
auto x1 = 5;// Non-compliant - initializer is of fundamental type
auto x2 = 0.3F; // Non-compliant - initializer is of fundamental type
auto x3 = {8};
// Non-compliant - initializer is of fundamental type

std::vector<std::int32_t> v;
auto x4 = v.size(); // Compliant with case (1) - x4 is of size_t type that
// is returned from v.size() method

auto a = A{}; // Compliant with case (2)

auto lambda1 = []() -> std::uint16_t {
return 5U;
}; // Compliant with case (2) - lambda1 is of non-fundamental lambda
// expression type
auto x5 = lambda1(); // Compliant with case (1) - x5 is of
// std::uint16_t type
}
void F2() noexcept
{
auto lambda1 = [](auto x, auto y) -> decltype(x + y) {
return (x + y);
};
// Compliant with cases (2) and (3)
auto y1 = lambda1(5.0, 10); // Compliant with case (1)
}
template <typename T, typename U>
auto F3(T t, U u) noexcept -> decltype(t + u) // Compliant with case (4)
{
return (t + u);
}
template <typename T>
class B
{

public:
T Fn(T t);
};
template <typename T>
auto B<T>::Fn(T t) -> T // Compliant with case (4)
{
// ...
return t;
}

See also

HIC++ v4.0 [9]: 7.1.8 Use auto id = expr when declaring a variable to have the same type as its initializer function call. C++ Core Guidelines [11]: Use auto. Google C++ Style Guide [12]: Use auto to avoid type names that are noisy, obvious, or unimportant.

Rule A7-1-6 (required, implementation, automated)

The typedef specifier shall not be used.

Rationale

The typedef specifier can not be easily used for defining alias templates. Also, the typedef syntax makes the code less readable. For defining aliases, as well as template aliases, it is recommended to use the using syntax instead of the typedef. Note that active issues related to the using syntax are listed below, in the “See also” section.

Example

// $Id: A7-1-6.cpp 271687 2017-03-23 08:57:35Z piotr.tanski $
#include <cstdint>
#include <type_traits>

typedef std::int32_t (*fPointer1)(std::int32_t); // Non-compliant

using fPointer2 = std::int32_t (*)(std::int32_t); // Compliant

// template<typename T>

// typedef std::int32_t (*fPointer3)(T); // Non-compliant - compilation error

template <typename T>

using fPointer3 = std::int32_t (*)(T); // Compliant

See also

C++ Core Guidelines [11]: T.43: Prefer using over typedef for defining aliases C++ Standard Core Language Active Issues, Revision 96 [18]: 1554. Access and alias templates. C++ Standard Core Language Defect Reports and Accepted Issues, Revision 96 [18]: 1558. Unused arguments in alias template specializations.

Rule A7-1-7 (required, implementation, automated)

Each expression statement and identifier declaration shall be placed on a separate line.

Rationale

Declaring an identifier on a separate line makes the identifier declaration easier to find and the source code more readable. Also, combining objects, references and pointers declarations with assignments and function calls on the same line may become confusing.

Exception

It is permitted to declare identifiers in initialization statement of a for loop.

Example

// $Id: A7-1-7.cpp 292454 2017-10-23 13:14:23Z michal.szczepankiewicz $
#include <cstdint>
#include <vector>

typedef std::int32_t* ptr;

// Compliant

typedef std::int32_t *pointer, value; // Non-compliant

void Fn1() noexcept
{
std::int32_t x = 0;
std::int32_t const *p2, z = 1;

// Compliant

std::int32_t y = 7, *p1 = nullptr; // Non-compliant

// Non-compliant

}

void Fn2()
{
std::vector<std::int32_t> v{1, 2, 3, 4, 5};
for (auto iter{v.begin()}, end{v.end()}; iter != end;
++iter) // Compliant by exception
{
// ...
}
}

void Fn3() noexcept
{

std::int32_t x{5};
std::int32_t y{15}; // Non-compliant
x++;
++y; // Non-compliant
for (std::int32_t i{0}; i < 100; ++i)
{
Fn2(); // Compliant
}

}

See also

HIC++ v4.0 [9]: 7.1.1 Declare each identifier on a separate line in a separate declaration. JSF December 2005 [8]: AV Rule 42 Each expression-statement will be on a separate line. JSF December 2005 [8]: AV Rule 152: Multiple variable declarations shall not be allowed on the same line. C++ Core Guidelines [11]: NL.20: Don’t place two statements on the same line.

Rule A7-1-8 (required, implementation, automated)

A non-type specifier shall be placed before a type specifier in a declaration.

Rationale

Placing a non-type specifier, i.e. typedef, friend, constexpr, register, static, extern, thread_local, mutable, inline, virtual, explicit, before type specifiers makes the source code more readable.

Example

// $Id: A7-1-8.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <cstdint>

typedef std::int32_t int1; // Compliant
std::int32_t typedef int2; // Non-compliant

class C
{
public:
virtual inline void F1(); // Compliant
inline virtual void F2(); // Compliant
void virtual inline F3(); // Non-compliant
private:
std::int32_t mutable x; // Non-compliant
mutable std::int32_t y; // Compliant
};

See also

HIC++ v4.0 [9]: 7.1.3 Do not place type specifiers before non-type specifiers in a declaration.

Rule A7-1-9 (required, implementation, automated)

A class, structure, or enumeration shall not be declared in the definition of its type.

Rationale

Combining a type definition with a declaration of another entity can lead to readability problems and can be confusing for a developer.

Example

// $Id: A7-1-9.cpp 305629 2018-01-29 13:29:25Z piotr.serwa $
#include <cstdint>

enum class DIRECTION
{
UP,
DOWN
} dir;
//non-compliant

class Foo
{
public:
enum class ONE {AA, BB}; //compliant

static constexpr enum class TWO {CC, DD} sVar = TWO::CC; // non-compliant
static constexpr ONE sVar2 = ONE::AA; //compliant

};

struct Bar
{
std::uint32_t a;
} barObj; //non-compliant

struct Bar2
{
std::uint32_t a;
} bar2Obj, *bar2Ptr; //non-compliant, also with A7-1-7

struct Foo2
{
std::uint32_t f;
};

Foo2 foo2Obj; //compliant

See also

JSF December 2005 [8]: AV Rule 141: A class, structure, or enumeration will not be declared in the definition of its type. C++ Core Guidelines [11]: C.7: Don’t define a class or enum and declare a variable of its type in the same statement.

Rule A7-2-1 (required, implementation, automated)

An expression with enum underlying type shall only have values corresponding to the enumerators of the enumeration.

Rationale

It is unspecified behavior if the evaluation of an expression with enum underlying type yields a value which does not correspond to one of the enumerators of the enumeration.

Additionally, other rules in this standard assume that objects of enum type only contain values corresponding to the enumerators. This rule ensures the validity of these assumptions. One way of ensuring compliance when converting to an enumeration is to use a switch statement.

Example

// $Id: A7-2-1.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <cstdint>
enum class E : std::uint8_t
{
Ok = 0,
Repeat,
Error
};
E Convert1(std::uint8_t number) noexcept
{
E result = E::Ok; // Compliant
switch (number)
{
case 0:
{
result
= E::Ok; // Compliant
break;
}
case 1:
{
result = E::Repeat; // Compliant

break;
}
case 2:
{
result
= E::Error; // Compliant
break;
}
case 3:
{
constexpr std::int8_t val = 3;
result
= static_cast<E>(val); // Non-compliant - value 3 does not
// correspond to any of E’s
// enumerators
break;
}
default:
{
result
=
static_cast<E>(0); // Compliant - value 0 corresponds to E::Ok
break;
}
}
return result;
}
E Convert2(std::uint8_t userInput) noexcept
{
E result = static_cast<E>(userInput); // Non-compliant - the range of
// userInput may not correspond to
// any of E’s enumerators
return result;
}
E Convert3(std::uint8_t userInput) noexcept
{
E result = E::Error;
if (userInput < 3)
{
result = static_cast<E>(userInput); // Compliant - the range of
// userInput checked before casting
// it to E enumerator
}
return result;
}

See also

MISRA C++ 2008 [7]: Rule 7-2-1 An expression with enum underlying type shall only have values corresponding to the enumerators of the enumeration.

Rule A7-2-2 (required, implementation, automated)

Enumeration underlying base type shall be explicitly defined.

Rationale

The enumeration underlying type is implementation-defined, with the only restriction that the type must be able to represent the enumeration values. Although scoped enum will implicitly define an underlying type of int, the underlying base type of enumeration should always be explicitly defined with a type that will be large enough to store all enumerators.

Example

// $Id: A7-2-2.cpp 271715 2017-03-23 10:13:51Z piotr.tanski $
#include <cstdint>
enum class E1 // Non-compliant
{
E10,
E11,
E12
};
enum class E2 : std::uint8_t // Compliant
{
E20,
E21,
E22
};
enum E3 // Non-compliant
{
E30,
E31,
E32
};
enum E4 : std::uint8_t // Compliant - violating another rule
{
E40,
E41,
E42
};
enum class E5 : std::uint8_t // Non-compliant - will not compile
{
E50 = 255,
// E5_1, // E5_1 = 256 which is outside of range of underlying type
// std::uint8_t
// - compilation error
// E5_2 // E5_2 = 257 which is outside of range of underlying type
// std::uint8_t
// - compilation error
};

See also

HIC++ v4.0 [9]: 7.2.1 Use an explicit enumeration base and ensure that it is large enough to store all enumerators

Rule A7-2-3 (required, implementation, automated)

Enumerations shall be declared as scoped enum classes.

Rationale

If unscoped enumeration enum is declared in a global scope, then its values can redeclare constants declared with the same identifier in the global scope. This may lead to developer’s confusion. Using enum-class as enumeration encloses its enumerators in its inner scope and prevent redeclaring identifiers from outer scope. Note that enum class enumerators disallow implicit conversion to numeric values.

Example

// $Id: A7-2-3.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <cstdint>

enum E1 : std::int32_t // Non-compliant
{
E10,
E11,
E12
};

enum class E2 : std::int32_t // Compliant
{
E20,
E21,
E22
};

// static std::int32_t E1_0 = 5; // E1_0 symbol redeclaration, compilation
// error

static std::int32_t e20 = 5; // No redeclarations, no compilation error

extern void F1(std::int32_t number)
{
}

void F2()
{
F1(0);

F1(E11); // Implicit conversion from enum to std::int32_t type

// f1(E2::E2_1); // Implicit conversion not possible, compilation error

F1(static_cast<std::int32_t>(
E2::E21)); // Only explicit conversion allows to
// pass E2_1 value to f1() function

}

See also

C++ Core Guidelines [11]: Enum.3: Prefer class enums over "‘plain"’ enums.

Rule A7-2-4 (required, implementation, automated)

In an enumeration, either (1) none, (2) the first or (3) all enumerators shall be initialized.

Rationale

Explicit initialization of only some enumerators in an enumeration, and relying on compiler to initialize the remaining ones, may lead to developer‘s confusion.

Example

//% $Id: A7-2-4.cpp 271715 2017-03-23 10:13:51Z piotr.tanski $
#include <cstdint>
enum class Enum1 : std::uint32_t
{
One,
Two = 2, // Non-compliant
Three
};
enum class Enum2 : std::uint32_t // Compliant (none)
{
One,
Two,
Three
};
enum class Enum3 : std::uint32_t // Compliant (the first)
{
One = 1,
Two,
Three
};
enum class Enum4 : std::uint32_t // Compliant (all)
{
One = 1,
Two = 2,
Three = 3
};

See also

MISRA C++ 2008 [7]: Rule 8-5-3 In an enumerator list, the = construct shall not be used to explicitly initialize members other than the first, unless all items are explicitly initialized. HIC++ v4.0 [9]: 7.2.2 Initialize none, the first only or all enumerators in an enumeration.

Rule A7-2-5 (advisory, design, non-automated)

Enumerations should be used to represent sets of related named constants.

Rationale

Explicit declaration of constants as an enumeration clearly shows that they are related, which enhances readability and maintenance. Note: Using switch statement on an enumeration is a common case and such an approach helps to detect errors, see M6-4-6.

Example

//% $Id: A7-2-5.cpp 305629 2018-01-29 13:29:25Z piotr.serwa $
#include <cstdint>
//compliant
enum class WebpageColors: std::uint32_t
{
Red,
Blue,
Green
};
//non-compliant
enum class Misc: std::uint32_t
{
Yellow,
Monday,
Holiday
};

See also

JSF December 2005 [8]: AV Rule 148: Enumeration types shall be used instead of integer types (and constants) to select from a limited series of choices. C++ Core Guidelines [11]: Enum.2: Use enumerations to represent sets of related named constants.

Rule M7-3-1 (required, implementation, automated)

The global namespace shall only contain main, namespace declarations and extern "C" declarations. See MISRA C++ 2008 [7]

Rule M7-3-2 (required, implementation, automated)

The identifier main shall not be used for a function other than the global function main.

See MISRA C++ 2008 [7]

Rule M7-3-3 (required, implementation, automated)

There shall be no unnamed namespaces in header files.

See MISRA C++ 2008 [7]

Rule M7-3-4 (required, implementation, automated)

Using-directives shall not be used. See MISRA C++ 2008 [7] See: Using-directive [16] concerns an inclusion of specific namespace with all its types, e.g. using namespace std.

Rule A7-3-1 (required, implementation, automated)

All overloads of a function shall be visible from where it is called.

Rationale

Additional identifiers introduced by a using declaration makes only prior declarations of this identifier visible. Any potential subsequent declarations will not be added to the current scope, which may lead to unexpected results and developers confusion. Overriding or overloading a member function in a derived class causes other member functions with the same name to be hidden. Thus, a potential function call may result in a different function being called depending on if the call was made using the derived or base class reference/pointer. Introducing hidden names into the derived class by a using declaration helps to avoid such misleading situations.

Example

// $Id: A7-3-1.cpp 312801 2018-03-21 16:17:05Z michal.szczepankiewicz $
#include <cstdint>

class Base
{
public:
void P(uint32_t);

virtual void V(uint32_t);
virtual void V(double);

};

class NonCompliant : public Base
{
public:
//hides P(uint32_t) when calling from the
//derived class
void P(double);
//hides V(uint32_t) when calling from the
//derived class
void V(double) override;
};

class Compliant : public Base
{
public:
//both P(uint32_t) and P(double) available
//from the derived class
using Base::P;
void P(double);

//both P(uint32_t) and P(double)
using Base::V;
void V(double) override;

};

void F1()
{
NonCompliant d{};
d.P(0U); // D::P (double) called
Base& b{d};
b.P(0U); // NonCompliant::P (uint32_t) called

d.V(0U); // D::V (double) called
b.V(0U); // NonCompliant::V (uint32_t) called

}

void F2()
{
Compliant d{};
d.P(0U); // Compliant::P (uint32_t) called

Base& b{d};
b.P(0U); // Compliant::P (uint32_t) called

d.V(0U); // Compliant::V (uint32_t) called
b.V(0U); // Compliant::V (uint32_t) called

}

namespace NS
{
void F(uint16_t);
}

//includes only preceding declarations into
//the current scope
using NS::F;

namespace NS
{
void F(uint32_t);
}

void B(uint32_t b)
{
//non-compliant, only F(uint16_t) is available
//in this scope
F(b);
}

See also

MISRA C++ 2008 [7]: 7-3-5: Multiple declarations for an identifier in the same namespace shall not straddle a using-declaration for that identifier. HIC++ v4.0 [9]: 13.1.1: Ensure that all overloads of a function are visible from where it is called. Rule M7-3-6 (required, implementation, automated) Using-directives and using-declarations (excluding class scope or function scope usingdeclarations) shall not be used in header files. See MISRA C++ 2008 [7] See: Using-declaration [16] concerns an inclusion of specific type, e.g. using std::string.

Rule A7-4-1 (required, implementation, automated)

The asm declaration shall not be used.

Rationale

Inline assembly code restricts the portability of the code.

Example

// $Id: A7-4-1.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <cstdint>
std::int32_t Fn1(std::int32_t b) noexcept
{
std::int32_t ret = 0;
// ...
asm("pushq %%rax \n"
"movl %0, %%eax \n"
"addl %1, %%eax \n"
"movl %%eax, %0 \n"
"popq %%rax"
: "=r"(ret)
: "r"(b)); // Non-compliant
return ret;
}
std::int32_t Fn2(std::int32_t b) noexcept
{
std::int32_t ret = 0;
// ...
ret += b; // Compliant - equivalent to asm(...) above
return ret;
}

See also

HIC++ v4.0 [9]: 7.5.1 Do not use the asm declaration.

Rule M7-4-1 (required, implementation, non-automated)

All usage of assembler shall be documented. See MISRA C++ 2008 [7]

Rule M7-4-2 (required, implementation, automated)

Assembler instructions shall only be introduced using the asm declaration. See MISRA C++ 2008 [7]

Rule M7-4-3 (required, implementation, automated)

Assembly language shall be encapsulated and isolated.

See MISRA C++ 2008 [7]

Rule M7-5-1 (required, implementation, non-automated)

A function shall not return a reference or a pointer to an automatic variable (including parameters), defined within the function. See MISRA C++ 2008 [7]

Rule M7-5-2 (required, implementation, non-automated)

The address of an object with automatic storage shall not be assigned to another object that may persist after the first object has ceased to exist. See MISRA C++ 2008 [7] Note: C++ specifies that binding a temporary object (e.g. automatic variable returned from a function) to a reference to const prolongs the lifetime of the temporary to the lifetime of the reference. Note: Rule 7-5-2 concerns C++11 smart pointers, i.e. std::unique_ptr, std::shared_ptr and std::weak_ptr, too.


## See also
C++ Core Guidelines [11]: F.45: Don’t return a T&&.

Rule A7-5-1 (required, implementation, automated)

A function shall not return a reference or a pointer to a parameter that is passed by reference to const.

Rationale

“[...] Where a parameter is of const reference type a temporary object is introduced if needed (7.1.6, 2.13, 2.13.5, 8.3.4, 12.2).” [C++14 Language Standard [3]] Any attempt to dereferencing an object which outlived its scope will lead to undefined behavior. References to const bind to both lvalues and rvalues, so functions that accept parameters passed by reference to const should expect temporary objects too.

Returning a pointer or a reference to such an object leads to undefined behavior on accessing it.

Example

// $Id: A7-5-1.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <cstdint>
class A
{
public:
explicit A(std::uint8_t n) : number(n) {}
~A() { number = 0U; }
// Implementation

private:
std::uint8_t number;
};
const A& Fn1(const A& ref) noexcept // Non-compliant - the function returns a
// reference to
const reference parameter
// which may
bind to temporary
objects.
// According
to C++14 Language Standard, it
// is undefined whether a temporary object is introduced for const
// reference
// parameter
{
// ...
return ref;
}
const A& Fn2(A& ref) noexcept // Compliant - non-const reference parameter does
// not bind
to temporary objects, it is allowed
// that the
function returns a reference to such
//
a parameter
{
// ...
return ref;
}

const A* Fn3(const A& ref) noexcept // Non-compliant - the function returns a

// pointer to const reference parameter
// which may bind to temporary objects.
// According to C++14 Language Standard, it
// is undefined whether a temporary object is introduced for const
// reference
// parameter
{
// ...
return &ref;
}
template <typename T>
T& Fn4(T& v) // Compliant - the function will not bind to temporary objects
{
// ...
return v;

}
void F() noexcept
{
A a{5};
const A& ref1 = Fn1(a); // fn1 called with an lvalue parameter from an
// outer scope, ref1 refers to valid object
const A& ref2 = Fn2(a); // fn2 called with an lvalue parameter from an
// outer scope, ref2 refers to valid object

const A* ptr1 = Fn3(a); // fn3 called with an lvalue parameter from an

// outer scope, ptr1 refers to valid object
const A& ref3 = Fn4(a); // fn4 called with T = A, an lvalue parameter from
// an outer scope, ref3 refers to valid object

const A& ref4 = Fn1(A{10}); // fn1 called with an rvalue parameter
// (temporary), ref3 refers to destroyed object
// A const& ref5 = fn2(A{10}); // Compilation
// error - invalid initialization of non-const
// reference

const A* ptr2 = Fn3(A{15}); // fn3 called with an rvalue parameter

// (temporary), ptr2 refers to destroyted
// object
// const A& ref6 = fn4(A{20}); // Compilation error - invalid
// initialization of non-const reference

}

See also

MISRA C++ 2008 [7]: A function shall not return a reference or a pointer to a parameter that is passed by reference or const reference.

Rule A7-5-2 (required, implementation, automated)

Functions shall not call themselves, either directly or indirectly.

Rationale

As the stack space is limited resource, use of recursion may lead to stack overflow at run-time. It also may limit the scalability and portability of the program. Recursion can be replaced with loops, iterative algorithms or worklists.

Exception

Recursion in variadic template functions used to process template arguments does not violate this rule, as variadic template arguments are evaluated at compile time and the call depth is known. Recursion of a constexpr function does not violate this rule, as it is evaluated at compile time.

Example

// $Id: A7-5-2.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <cstdint>
static std::int32_t Fn1(std::int32_t number);
static std::int32_t Fn2(std::int32_t number);
static std::int32_t Fn3(std::int32_t number);
static std::int32_t Fn4(std::int32_t number);
std::int32_t Fn1(std::int32_t number)
{
if (number > 1)
{
number = number * Fn1(number - 1); // Non-compliant

}

return number;
}
std::int32_t Fn2(std::int32_t number)
{
for (std::int32_t n = number; n > 1; --n) // Compliant
{
number = number * (n - 1);

}

return number;
}
std::int32_t Fn3(std::int32_t number)
{
if (number > 1)
{
number = number * Fn3(number - 1); // Non-compliant

}

return number;
}
std::int32_t Fn4(std::int32_t number)
{
if (number == 1)
{
number = number * Fn3(number - 1); // Non-compliant

}

return number;
}
template <typename T>
T Fn5(T value)
{
return value;
}
template <typename T, typename... Args>
T Fn5(T first, Args... args)
{
return first + Fn5(args...); // Compliant by exception - all of the

// arguments are known during compile time
}
std::int32_t Fn6() noexcept
{
std::int32_t sum = Fn5<std::int32_t, std::uint8_t, float, double>(
10, 5, 2.5, 3.5); // An example call to variadic template function
// ...
return sum;
}
constexpr std::int32_t Fn7(std::int32_t x, std::int8_t n)
{
if (n >= 0)
{
x += x;
return Fn5(x, --n); // Compliant by exception - recursion evaluated at
// compile time
}
return x;
}

See also

MISRA C++ 2008 [7]: Rule 7-5-4 Functions should not call themselves, either directly or indirectly. JSF December 2005 [8]: AV Rule 119 Functions shall not call themselves, either directly or indirectly (i.e. recursion shall not be allowed). HIC++ v4.0 [9]: 5.2.2 Ensure that functions do not call themselves, either directly or indirectly.

Rule A7-6-1 (required, implementation, automated)

Functions declared with the [[noreturn]] attribute shall not return.

Rationale

The C++ standard specifies that functions with the [[noreturn]] attribute shall not return. Returning from such a function can be prohibited in the following way: throwing an exception, entering an infinite loop, or calling another function with the [[noreturn]] attribute. Returning from such a function leads to undefined behavior.

// $Id: A7-6-1.cpp 305629 2018-01-29 13:29:25Z piotr.serwa $
#include <cstdint>
#include <exception>

class PositiveInputException : public std::exception {};

[[noreturn]] void f(int i) //non-compliant
{
if (i > 0)
{
throw PositiveInputException();
}
//undefined behaviour for non-positive i
}

[[noreturn]] void g(int i) //compliant
{
if (i > 0)
{
throw "Received positive input";
}

while(1)
{
//do processing
}

}

See also

SEI CERT C++ Coding Standard [10]: MSC53-CPP: Do not return from a function declared [[noreturn]].

Rule M8-0-1 (required, implementation, automated)

An init-declarator-list or a member-declarator-list shall consist of a single init-declarator or member-declarator respectively. See MISRA C++ 2008 [7]

Rule A8-2-1 (required, implementation, automated)

When declaring function templates, the trailing return type syntax shall be used if the return type depends on the type of parameters.

Rationale

Use of trailing return type syntax avoids a fully qualified return type of a function along with the typename keyword.

Example

// $Id: A8-2-1.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <cstdint>
template <typename T>
class A
{
public:
using Type = std::int32_t;

Type F(T const&) noexcept;
Type G(T const&) noexcept;
};
template <typename T>
typename A<T>::Type A<T>::F(T const&) noexcept // Non-compliant
{
// Implementation
}
template <typename T>
auto A<T>::G(T const&) noexcept -> Type // Compliant
{
// Implementation
}

See also

HIC++ v4.0 [9]: 7.1.7 Use a trailing return type in preference to type disambiguation using typename.

Rule M8-3-1 (required, implementation, automated)

Parameters in an overriding virtual function shall either use the same default arguments as the function they override, or else shall not specify any default arguments. See MISRA C++ 2008 [7] Note: Overriding non-virtual functions in a subclass is called function “hiding” or “redefining”. It is prohibited by A10-2-1.

Rule A8-4-1 (required, implementation, automated)

Functions shall not be defined using the ellipsis notation.

Rationale

Passing arguments via an ellipsis bypasses the type checking performed by the compiler. Additionally, passing an argument with non-POD class type leads to undefined behavior. Variadic templates offer a type-safe alternative for ellipsis notation. If use of a variadic template is not possible, function overloading or function call chaining can be considered.

Example

// $Id: A8-4-1.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $

void Print1(char* format, ...) // Non-compliant - variadic arguments are used

{
// ...

}

template <typename First, typename... Rest>
void Print2(const First& first, const Rest&... args) // Compliant
{
// ...
}

See also

MISRA C++ 2008 [7]: Rule 8-4-1 Functions shall not be defined using the ellipsis notation. HIC++ v4.0 [9]: 14.1.1 Use variadic templates rather than an ellipsis. C++ Core Guidelines [11]: Type.8: Avoid reading from varargs or passing vararg arguments. Prefer variadic template parameters instead. C++ Core Guidelines [11]: F.55: Don’t use va_arg arguments.

Rule M8-4-2 (required, implementation, automated)

The identifiers used for the parameters in a re-declaration of a function shall be identical to those in the declaration. See MISRA C++ 2008 [7]

Rule A8-4-2 (required, implementation, automated)

All exit paths from a function with non-void return type shall have an explicit return statement with an expression.

Rationale

In a function with non-void return type, return expression gives the value that the function returns. The absence of a return with an expression leads to undefined behavior (and the compiler may not give an error).

Exception

A function may additionally exit due to exception handling (i.e. a throw statement).

Example

// $Id: A8-4-2.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <cstdint>
#include <stdexcept>
std::int32_t F1() noexcept // Non-compliant
{
}
std::int32_t F2(std::int32_t x) noexcept(false)
{
if (x > 100)
{
throw std::logic_error("Logic Error"); // Compliant by exception
}

return x; // Compliant
}
std::int32_t F3(std::int32_t x, std::int32_t y)
{
if (x > 100 || y > 100)
{
throw std::logic_error("Logic Error"); // Compliant by exception
}
if (y > x)
{
return (y - x); // Compliant
}
return (x - y); // Compliant
}

See also

MISRA C++ 2008 [7]: Rule 8-4-3 All exit paths from a function with non-void return type shall have an explicit return statement with an expression. SEI CERT C++ [10]: MSC52-CPP. Value-returning functions must return a value from all exit paths.

Rule M8-4-4 (required, implementation, automated)

A function identifier shall either be used to call the function or it shall be preceded by &. See MISRA C++ 2008 [7] Rule A8-4-3 (advisory, design, non-automated) Common ways of passing parameters should be used.

Rationale

Using common and well-understood parameter passing patterns as summarised in the following table helps meeting developer expectations. in in/out out consume forward

cheap to copy or move only f(X)

cheap to move expensive to move f(const X &) f(X &) X f() f(X &) f(X &&) template f(T &&)

Parameter passing

Example

// $Id: A8-4-3.cpp 308906 2018-02-23 15:34:15Z christof.meerwald $

#include <algorithm>
#include <array>
#include <cstdint>
#include <numeric>
#include <string>
#include <vector>

// Compliant: passing cheap-to-copy parameter by value
int32_t Increment(int32_t i)
{
return i + 1;
}

// Compliant: passing expensive to copy parameter by reference to const
int32_t Sum(const std::vector<int32_t> &v)
{
return std::accumulate(v.begin(), v.end(), 0);
}

// Compliant: passing in-out parameter by reference
void Decrement(int32_t &i)
{

--i;

}

// Compliant: returning out parameter by value
std::string GetGreeting()
{
return "Hello";
}

struct A
{
std::string text;
std::array<std::string, 1000> arr;
};

// Expensive to move "out" parameter passed by reference. If
// intentional, violation of A8-4-8 needs to be explained
void InitArray(std::array<std::string, 1000> &arr,
const std::string &text)
{
std::for_each(arr.begin(), arr.end(), [&text] (std::string &s) {
s = text;
});
}

// Compliant: passing in-out parameter by reference
void PopulateA(A &a)
{
InitArray(a.arr, a.text);
}

See also

C++ Core Guidelines [11]: F.16: Prefer simple and conventional ways of passing information

Rule A8-4-4 (advisory, design, automated)

Multiple output values from a function should be returned as a struct or tuple.

Rationale

Returning multiple values from a function using a struct or tuple clearly states output parameters and allows to avoid confusion of passing them as a reference in a function call. Returning a struct or tuple will not have an additional overhead for compilers that support return-value-optimization. In C++14, a returned tuple can be conveniently processed using std::tie at the call site, which will put the tuple elements directly into existing local variables. In C++17,

structured bindings allow to initialize local variables directly from members or elements of a returned struct or tuple. Note: For return types representing an abstraction, a struct should be preferred over a generic tuple. Note: This rule applies equally to std::pair, which is a special kind of tuple for exactly two elements.

Example

// $Id: A8-4-4.cpp 289816 2017-10-06 11:19:42Z michal.szczepankiewicz $

#include <tuple>

// Non-compliant, remainder returned as the output parameter
int Divide1(int dividend, int divisor, int& remainder)
{
remainder = dividend % divisor;
return dividend / divisor;
}

// Compliant, both quotient and remainder returned as a tuple
std::tuple<int, int> Divide2(int dividend, int divisor)
{
return std::make_tuple(dividend / divisor, dividend % divisor);
}

// Compliant since C++17, return tuple using list-initialization
// std::tuple<int, int> Divide3(int dividend, int divisor)
//{
//return { dividend / divisor, dividend % divisor };
//}

int main()
{
int quotient, remainder;
std::tie(quotient, remainder) = Divide2(26, 5); // store in local variables
// auto [quotient, remainder] = Divide3(26, 5); // since C++17, by
// structured bindings
return 0;
}

See also

C++ Core Guidelines [11]: F.21: To return multiple ”out” values, prefer returning a tuple or struct.

Rule A8-4-5 (required, design, automated)

”consume” parameters declared as X && shall always be moved from.

Rationale

A ”consume” parameter is declared with a type of rvalue reference to non-const nontemplate type (X &&). This documents that the value will be consumed in the function (i.e. left in a moved-from state) and requires an explicit ’std::move’ at the call site if an lvalue is passed to the function (an rvalue reference can implicitly bind only to an rvalue). Note: Other operations may be performed on the ”consume” parameter before being moved.

Example

// $Id: A8-4-5.cpp 305588 2018-01-29 11:07:35Z michal.szczepankiewicz $

#include <string>
#include <vector>

class A
{
public:
explicit A(std::vector<std::string> &&v)
: m_v{std::move(v)} // Compliant, move from consume parameter
{
}

private:
std::vector<std::string> m_v;

};

class B
{
public:
explicit B(std::vector<std::string> &&v)
: m_v{v} // Non-Compliant, consume parameter not moved from
{
}

std::vector<std::string> m_v;

};

See also

C++ Core Guidelines [11]: F.18: For ”consume” parameters, pass by X&& and std::move the parameter

Rule A8-4-6 (required, design, automated)

”forward” parameters declared as T && shall always be forwarded.

Rationale

A ”forward” parameter is declared with a type of forwarding reference (i.e. an rvalue reference to non-const template type (T &&)). As a forwarding reference can bind to both lvalues and rvalues, preserving lvalue-ness and cv qualifications, it is useful when forwarding a value to another function using ”std::forward”. However, as the parameter can bind to anything, it should only be used for forwarding without performing any other operations on the parameter. Note: A forwarding parameter can also be declared via ”auto &&” in a generic lambda

Example

// $Id: A8-4-6.cpp 305588 2018-01-29 11:07:35Z michal.szczepankiewicz $

#include <string>
#include <vector>

class A
{
public:
explicit A(std::vector<std::string> &&v);
};

class B
{
public:
explicit B(const std::vector<std::string> &v);
};

template<typename T, typename ... Args>
T make(Args && ... args)
{
return T{std::forward<Args>(args) ...}; // Compliant, forwarding args
}

int main()
{
make<A>(std::vector<std::string>{ });

std::vector<std::string> v;
make<B>(v);

}

See also

C++ Core Guidelines [11]: F.19: For ”forward” parameters, pass by TP&& and only std::forward the parameter A18-9-2 in section 6.18.9

Rule A8-4-7 (required, design, automated)

”in” parameters for ”cheap to copy” types shall be passed by value.

Rationale

Passing an argument by value documents that the argument won’t be modified. Copying the value (instead of passing by reference to const) also ensures that no indirection is needed in the function body to access the value. For the purpose of this rule, ”cheap to copy” is defined as a trivially copyable type that is no longer than two words (i.e. pointers).

Example

// $Id: A8-4-7.cpp 305588 2018-01-29 11:07:35Z michal.szczepankiewicz $

#include <cstdint>
#include <iostream>
#include <string>

// Compliant, pass by value
void output(std::uint32_t i)
{
std::cout << i << ’\n’;
}

// Non-Compliant, std::string is not trivially copyable
void output(std::string s)
{
std::cout << s << ’\n’;
}

struct A
{
std::uint32_t v1;
std::uint32_t v2;
};

// Non-Compliant, A is trivially copyable and no longer than two words
void output(const A &a)
{
std::cout << a.v1 << ", " << a.v2 << ’\n’;
}

See also

C++ Core Guidelines [11]: F.16: For ”in” parameters, pass cheaply-copied types by value and others by reference to const JSF December 2005 [8]: AV Rule 116: Small, concrete-type arguments (two or three words in size) should be passed by value if changes made to formal parameters should not be reflected in the calling function.

JSF December 2005 [8]: AV Rule 117.1: An object should be passed as const T& if the function should not change the value of the object. A18-9-2 in section 6.18.9

Rule A8-4-8 (required, design, automated)

Output parameters shall not be used.

Rationale

Output parameters are passed to a function as non-const references or pointers that can denote either in-out or out-only parameter. Using return value prevents from possible misuse of such a parameter. Note: Prefer returning non-value types (i.e. types in a inheritance hierarchy) as std::shared_ptr or std::unique_ptr.

Example

// $Id: A8-4-8.cpp 306164 2018-02-01 15:04:53Z christof.meerwald $

#include <iostream>
#include <vector>
// Compliant, return value
std::vector<int> SortOutOfPlace(const std::vector<int>& inVec);

// Non-compliant: return value as an out-parameter
void FindAll(const std::vector<int>& inVec, std::vector<int>& outVec);

struct B
{
};

struct BB
{
    B GetB() const& { return obj; }
    B&& GetB() && { return std::move(obj); }

    B obj;

};

// Non-compliant: returns a dangling reference
BB&& MakeBb1()
{
    return std::move(BB());
}

// Compliant: uses compiler copy-ellision
BB MakeBb2()
{
    return BB();

}

int main()
{
    BB x = MakeBb2();

    auto cpd = x.GetB();
    // copied value
    auto mvd = MakeBb2().GetB(); // moved value

    return 0;

}

See also

C++ Core Guidelines [11]: F.20: For ”out” output values, prefer return values to output parameters.

Rule A8-4-9 (required, design, automated)

”in-out” parameters declared as T & shall be modified.

Rationale

An ”in-out” parameter is declared with a type of reference to non-const. This means that a fully constructed object is passed into the function that can be read as well as modified. Note: Completely replacing the passed in object without reading any data from it would make it an ”out” parameter instead and is not considered compliant with this rule, also see rule: A8-4-8

Example

// $Id: A8-4-9.cpp 306178 2018-02-01 15:52:25Z christof.meerwald $

#include <cstdint>
#include <numeric>
#include <string>
#include <vector>

// Non-Compliant: does not modify the "in-out" parameter
int32_t Sum(std::vector<int32_t> &v)
{
    return std::accumulate(v.begin(), v.end(), 0);
}

// Compliant: Modifying "in-out" parameter
void AppendNewline(std::string &s)
{
    s += ’\n’;
}

// Non-Compliant: Replacing parameter value
void GetFileExtension(std::string &ext)
{
    ext = ".cpp";
}

See also

C++ Core Guidelines [11]: F.17: For ”in-out” parameters, pass by reference to non-const JSF December 2005 [8]: AV Rule 117.2: An object should be passed as T& if the function may change the value of the object.

Rule A8-4-10 (required, design, automated)

A parameter shall be passed by reference if it can’t be NULL

Rationale

Passing a parameter by pointer suggests that it can be NULL. If it can’t be NULL (i.e. it’s not optional) it should therefore be passed by reference instead. Only parameters that can be NULL shall be passed by pointer. Note: The C++ Library Fundamentals TS v2 defines std::observer_ptr as a near dropin replacement for raw pointers that makes it explicit that the object is not owned by the pointer. Note: boost::optional supports reference types, and in C++17 std::optional can be used in conjunction with std::reference_wrapper (using std::optional with a value type would create an undesirable copy of the object)

Example

// $Id: A8-4-10.cpp 307966 2018-02-16 16:03:46Z christof.meerwald $

#include <cstdint>
#include <numeric>
#include <vector>

// Non-Compliant: non-optional parameter passed by pointer

int32_t Sum(const std::vector<int32_t> *v)

{
return std::accumulate(v->begin(), v->end(), 0);

}

// Compliant: non-optional parameter passed by reference
int32_t Sum(const std::vector<int32_t> &v)
{
return std::accumulate(v.begin(), v.end(), 0);
}

See also

C++ Core Guidelines [11]: F.60: Prefer T* over T& when "no argument" is a valid option JSF December 2005 [8]: AV Rule 118: Arguments should be passed via pointers if NULL values are possible. JSF December 2005 [8]: AV Rule 118.1: An object should be passed as const T* if its value should not be modified. JSF December 2005 [8]: AV Rule 118.2: An object should be passed as T* if its value may be modified.

Rule A8-4-11 (required, design, automated)

A smart pointer shall only be used as a parameter type if it expresses lifetime semantics

Rationale

If the object passed into the function is merely used without affecting the lifetime, it is preferable to pass it by reference or raw pointer instead. Keeping a copy of a std::shared_ptr or moving a std::unique_ptr would be examples that affect the lifetime. Note: When an object whose lifetime is managed by a non-local smart pointer is passed by reference or raw pointer, care needs to be taken that the lifetime of the object doesn’t end during the duration of the called function. In the case of a std::shared_ptr this can be achieved by keeping a local copy of the shared_ptr.

Exception

A non-owning smart pointer, like std::observer_ptr from the C++ Library Fundamentals TS v2, that documents the non-owning property of the parameter does not violate this rule.

Example

// $Id: A8-4-11.cpp 307966 2018-02-16 16:03:46Z christof.meerwald $

#include <cstdint>
#include <memory>
#include <numeric>
#include <vector>

class A
{
public:
void do_stuff();
};

// Non-Compliant: passing object as smart pointer
void foo(std::shared_ptr<A> a)
{
if (a)
{
a->do_stuff();
}
else
{
// ...
}
}

// Compliant: passing as raw pointer instead

void bar(A *a)

{
if (a != nullptr)
{
a->do_stuff();
}
else
{
// ...
}

}

class B
{
public:
void add_a(std::shared_ptr<A> a)
{
m_v.push_back(a);
}

private:
std::vector<std::shared_ptr<A>> m_v;

};

// Compliant: storing the shared pointer (affecting lifetime)
void bar(B &b, std::shared_ptr<A> a)
{
b.add_a(a);
}

See also

C++ Core Guidelines [11]: R.30: Take smart pointers as parameters only to explicitly express lifetime semantics.

C++ Core Guidelines [11]: R.37: Do not pass a pointer or reference obtained from an aliased smart pointer. C++ Core Guidelines [11]: F.7: For general use, take T* or T& arguments rather than smart pointers. A18-5-2 in section 6.18.5

Rule A8-4-12 (required, design, automated)

A std::unique_ptr shall be passed to a function as: (1) a copy to express the function assumes ownership (2) an lvalue reference to express that the function replaces the managed object.

Rationale

Transferring ownership in the (1) case is unconditional. A temporary std::unique_ptr is constructed implicitly and move-initialized from the caller’s std::unique_ptr and then passed to the function. This guarantees that the caller’s std::unique_ptr object is empty. Passing an lvalue reference is suggested to be used if a called function is supposed to replace the object managed by the passed std::unique_ptr, e.g. call assignment operator or reset method. Otherwise, it is recommended to pass an lvalue reference to the underlying object instead, see A8-4-11, A8-4-10. Note: Passing a const lvalue reference to std::unique_ptr does not take ownership and does not allow to replace the managed object. Also, the const qualifier does not apply to the underlying object, but to the smart pointer itself. It is suggested to pass a const lvalue reference to the underlying object instead, see A8-4-11, A8-4-10.

Exception

It is allowed to transfer ownership by passing a std::unique_ptr by an rvalue reference in case this reference is moved into a std::unique_ptr object inside the called function.

Example

// $Id: A8-4-12.cpp 308795 2018-02-23 09:27:03Z michal.szczepankiewicz $

#include <memory>
#include <iostream>

//compliant, transfers an ownership
void Value(std::unique_ptr<int> v) { }

//compliant, replaces the managed object
void Lv1(std::unique_ptr<int>& v)
{
v.reset();
}

//non-compliant, does not replace the managed object
void Lv2(std::unique_ptr<int>& v) {}

//compliant by exception
void Rv1(std::unique_ptr<int>&& r)
{
std::unique_ptr<int> v(std::move(r));
}

//non-compliant
void Rv2(std::unique_ptr<int>&& r) {}

int main(void)
{
auto sp = std::make_unique<int>(7);
Value(std::move(sp));
//sp is empty

auto sp2 = std::make_unique<int>(9);
Rv1(std::move(sp2));
//sp2 is empty, because it was moved from in Rv1 function

auto sp3 = std::make_unique<int>(9);
Rv2(std::move(sp3));
//sp3 is not empty, because it was not moved from in Rv1 function

return 0;

}

See also

HIC++ v4.0 [9]: 8.2.4: Do not pass std::unique_ptr by const reference. C++ Core Guidelines [11]: R.32: Take a unique_ptr parameter to express that a function assumes ownership of a widget. C++ Core Guidelines [11]: R.33: Take a unique_ptr& parameter to express that a function reseats the widget. C++ Core Guidelines [11]: I.11: Never transfer ownership by a raw pointer (T*) or reference (T&).

Rule A8-4-13 (required, design, automated)

A std::shared_ptr shall be passed to a function as: (1) a copy to express the function shares ownership (2) an lvalue reference to express that the function replaces the managed object (3) a const lvalue reference to express that the function retains a reference count.

Rationale

Passing a std::shared_ptr by value (1) is clear and makes ownership sharing explicit. Passing an lvalue reference (2) to std::shared_ptr is suggested to be used if a called function replaces the managed object on at least one code path, e.g. call assignment operator or reset method. Otherwise, it is recommended to pass an lvalue reference to the underlying object instead, see A8-4-11, A8-4-10. Functions that take a const lvalue reference (3) to std::shared_ptr as a parameter are supposed to copy it to another std::shared_ptr on at least one code path, otherwise the parameter should be passed by a const lvalue reference to the underlying object instead, see A8-4-11, A8-4-10.

Example

// $Id: A8-4-13.cpp 308795 2018-02-23 09:27:03Z michal.szczepankiewicz $

#include <memory>
#include <iostream>

//compliant, explicit ownership sharing
void Value(std::shared_ptr<int> v) { }

//compliant, replaces the managed object
void Lv1(std::shared_ptr<int>& v)
{
v.reset();
}

//non-compliant, does not replace the managed object
//shall be passed by int& so that API that does not
//extend lifetime of an object is not polluted
//with smart pointers
void Lv2(std::shared_ptr<int>& v)
{
++(*v);

}

//compliant, shared_ptr copied in the called function
void Clv1(const std::shared_ptr<int>& v)
{
Value(v);
}

//non-compliant, const lvalue reference not copied
//to a shared_ptr object on any code path
//shall be passed by const int&
void Clv2(const std::shared_ptr<int>& v)
{
std::cout << *v << std::endl;

}

//non-compliant
void Rv1(std::shared_ptr<int>&& r) {}

See also

C++ Core Guidelines [11]: R.34: Take a shared_ptr parameter to express that a function is part owner. C++ Core Guidelines [11]: R.35: Take a shared_ptr& parameter to express that a function might reseat the shared pointer. C++ Core Guidelines [11]: R.36: Take a const shared_ptr& parameter to express that it might retain a reference count to the object.

Rule A8-4-14 (required, design, non-automated)

Interfaces shall be precisely and strongly typed.

Rationale

Using precise and strong types in interfaces helps using them correctly. A large number of parameters of fundamental type (particularly of arithmetic type) can be an indication of bad interface design as it does not make it obvious what the units are, and there is no way for the compiler to warn when parameters are passed in the wrong order (as the types are the same or implicitly convertible). When several parameters are related, combining the parameters into a separate user-defined type should be considered. Similarly, a type of pointer to void does not provide any type safety and alternatives like a pointer to a common base class or using a (potentially constrained) template parameter should be considered.

Example

// $Id: A8-4-14.cpp 326058 2018-07-16 07:52:31Z christof.meerwald $

#include <cstdint>
#include <chrono>

// Non-compliant: unit of duration not obvious
void Sleep(std::uint32_t duration);

// Compliant: strongly typed
void Sleep(std::chrono::seconds duration);

// Non-compliant: list of related parameters with same type
void SetAlarm(std::uint32_t year, std::uint32_t month, std::uint32_t day,
std::uint32_t hour, std::uint32_t minute, std::uint32_t second);

// Compliant: strongly typed
void SetAlarm(std::chrono::system_clock::time_point const & when);

See also

C++ Core Guidelines [11]: I.4: Make interfaces precisely and strongly typed

Rule A8-5-0 (required, implementation, automated)

All memory shall be initialized before it is read.

Rationale

Objects with automatic or dynamic storage duration are default-initialized if no initializer is specified. Default initialization produces indeterminate values for objects of neither class nor array types. Default initialization of array types leads to default initialization of each array element. Reading from indeterminate values may produce undefined behavior. Thus, all local variables, member variables, or objects allocated dynamically must be explicitly initialized before their values are read, unless they are of class type or array of non-fundamental type. It is recommended practice to initialize all such objects immediately when they are defined. Note: Zero-initialization will happen before any other initialization for any objects with static or thread-local storage duration. Thus, such objects need not be explicitly initialized.

Example

// $Id: A8-5-0.cpp 307536 2018-02-14 12:35:11Z jan.babst $
#include <cstdint>
#include <string>

static std::int32_t zero; // Compliant - Variable with static storage duration
// is zero-initialized.

void local()
{
std::int32_t a;
// No initialization
std::int32_t b{}; // Compliant - zero initialization

b = a;
// Non-compliant - uninitialized memory read
a = zero; // Compliant - a is zero now
b = a;
// Compliant - read from initialized memory

std::string s; // Compliant - default constructor is a called
// read from s

}

void dynamic()
{
// Note: These examples violate A18-5-2

auto const a = new std::int32_t;
// No initialization
auto const b = new std::int32_t{}; // Compliant - zero initialization

*b = *a;

// Non-compliant - uninitialized memory read

*a = zero; // Compliant - a is zero now

*b = *a;

// Compliant - read from initialized memory

delete b;
delete a;

auto const s =
new std::string; // Compliant - default constructor is a called

// read from *s

delete s;

}

// Members of Bad are default-initialized by the (implicitly generated) default
// constructor. Note that this violates A12-1-1.
struct Bad
{
std::int32_t a;
std::int32_t b;
};

// Compliant - Members of Good are explicitly initialized.
// This also complies to A12-1-1.
struct Good
{
std::int32_t a{0};
std::int32_t b{0};
};

void members()
{
Bad bad; // Default constructor is called, but members a not initialized

bad.b = bad.a; // Non-compliant - uninitialized memory read
bad.a = zero;
// Compliant - bad.a is zero now
bad.b = bad.a; // Compliant - read from initialized memory

Good good; // Default constructor is called and initializes members

std::int32_t x = good.a; // Compliant

std::int32_t y = good.b; // Compliant

}

See also

MISRA C++ 2008 [7]: 8-5-1: All variables shall have a defined value before they are used. HIC++ v4.0 [9]: 8.4.1: Do not access an invalid object or an object with indeterminate value JSF December 2005 [8]: AV Rule 142: All variables shall be initialized before use. SEI CERT C++ Coding Standard [10]: EXP53-CPP: Do not read uninitialized memory C++ Core Guidelines [11]: ES.20: Always initialize an object ISO/IEC 14882:2014 [3]: 8.5: [dcl.init]

Rule A8-5-1 (required, implementation, automated)

In an initialization list, the order of initialization shall be following: (1) virtual base classes in depth and left to right order of the inheritance graph, (2) direct base classes in left to right order of inheritance list, (3) non-static data members in the order they were declared in the class definition.

Rationale

To avoid confusion and possible use of uninitialized data members, it is recommended that the initialization list matches the actual initialization order. Regardless of the order of member initializers in a initialization list, the order of initialization is always: Virtual base classes in depth and left to right order of the inheritance graph. Direct non-virtual base classes in left to right order of inheritance list.

Non-static member data in order of declaration in the class definition. Note that “The order of derivation is relevant only to determine the order of default initialization by constructors and cleanup by destructors.” [C++14 Language Standard [3]]

Example

// $Id: A8-5-1.cpp 271696 2017-03-23 09:23:09Z piotr.tanski $
#include <cstdint>
#include <string>
class A
{

};
class B
{
};
class C : public virtual B, public A
{
public:
C() : B(), A(), s() {} // Compliant

// C() : A(), B() { } // Non-compliant - incorrect order of initialization

private:
std::string s;

};
class D
{
};
class E
{
};
class F : public virtual A, public B, public virtual D, public E
{
public:
F() : A(), D(), B(), E(), number1(0), number2(0U) {} // Compliant
F(F const& oth)
: B(), E(), A(), D(), number1(oth.number1), number2(oth.number2)
{
} // Non-compliant - incorrect
// order of initialization

private:
std::int32_t number1;
std::uint8_t number2;

};

See also

HIC++ v4.0 [9]:12.4.4 Write members in an initialization list in the order in which they are declared

Rule M8-5-2 (required, implementation, automated)

Braces shall be used to indicate and match the structure in the nonzero initialization of arrays and structures. See MISRA C++ 2008 [7]

Rule A8-5-2 (required, implementation, automated) Bracedinitialization {}, without equals sign, shall be used for variable initialization.

Rationale

Braced-initialization using {} braces is simpler and less ambiguous than other forms of initialization. It is also safer, because it does not allow narrowing conversions for numeric values, and it is immune to C++’s most vexing parse. The use of an equals sign for initialization misleads into thinking that an assignment is taking place, even though it is not. For built-in types like int, the difference is academic, but for user-defined types, it is important to explicitly distinguish initialization from assignment, because different function calls are involved. Note that most vexing parse is a form of syntactic ambiguity resolution in C++, e.g. “Class c()” could be interpreted either as a variable definition of class “Class” or a function declaration which returns an object of type “Class”. Note that in order to avoid grammar ambiguities, it is highly recommended to use only braced-initialization {} within templates.

Exception

If a class declares both a constructor taking std::initializer_list argument and a constructor which invocation will be ignored in favor of std::initializer_list constructor, this rule is not violated by calling a constructor using () parentheses, see A8-5-4.

Example

// $Id: A8-5-2.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <cstdint>
#include <initializer_list>
void F1() noexcept
{
std::int32_t x1 =
// std::int32_t y {7.9}; // Compliant - compilation error, narrowing
std::int8_t x2{50};
// Compliant
std::int8_t x3 = {50}; // Non-compliant - std::int8_t x3 {50} is equivalent
// and more readable
std::int8_t x4 =
std::int8_t x5 = 300; // Non-compliant - narrowing occurs implicitly
std::int8_t x6(x5);
// Non-compliant
}
class A
{
public:
A(std::int32_t first, std::int32_t second) : x{first}, y{second} {}

private:
std::int32_t x;
std::int32_t y;

};
struct B
{
std::int16_t x;
std::int16_t y;
};
class C
{
public:
C(std::int32_t first, std::int32_t second) : x{first}, y{second} {}
C(std::initializer_list<std::int32_t> list) : x{0}, y{0} {}

private:
std::int32_t x;
std::int32_t y;

};
void F2() noexcept
{
A a1{1, 5};
// Compliant - calls constructor of class A
A a2 = {1, 5}; // Non-compliant - calls a default constructor of class A
// and not copy constructor or assignment operator.
A a3(1, 5);
// Non-compliant
B b1{5, 0};
// Compliant struct members initialization
C c1{2, 2};
// Compliant C(std::initializer_list<std::int32_t>)
// constructor
is
// called
C c2(2, 2);// Compliant by exception - this is the only way to call
// C(std::int32_t, std::int32_t) constructor
C c3{{}}; // Compliant - C(std::initializer_list<std::int32_t>) constructor
// is
// called with an empty initializer_list
C c4({2, 2}); // Compliant by exception // C(std::initializer_list<std::int32_t>)
// constructor is called
};
template <typename T, typename U>
void F1(T t, U u) noexcept(false)
{
std::int32_t x = 0;
T v1(x); // Non-compliant
T v2{x}; // Compliant - v2 is a variable
// auto y = T(u); // Non-compliant - is it construction or cast?
// Compilation error
};
void F3() noexcept
{
F1(0, "abcd"); // Compile-time error, cast from const char* to int

}

See also

C++ Core Guidelines [11]: ES.23 Prefer the {} initializer syntax. C++ Core Guidelines [11]: T.68: Use {} rather than () within templates to avoid ambiguities. C++ Core Guidelines [11]: ES.64: Use the T{e} notation for construction. Effective Modern C++ [13]: Item 7. Distinguish between () and {} when creating objects.

Rule A8-5-3 (required, implementation, automated)

A variable of type auto shall not be initialized using {} or ={} braced-initialization.

Rationale

If an initializer of a variable of type auto is enclosed in braces, then the result of type deduction may lead to developer confusion, as the variable initialized using {} or ={} will always be of std::initializer_list type. Note that some compilers, e.g. GCC or Clang, can implement this differently initializing a variable of type auto using {} will deduce an integer type, and initializing using ={} will deduce a std::initializer_list type. This is desirable type deduction which will be introduced into the C++ Language Standard with C++17.

Example

// $Id: A8-5-3.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <cstdint>
#include <initializer_list>

void Fn() noexcept
{
    auto x1(10); // Compliant - the auto-declared variable is of type int, but
                 // not compliant with A8-5-2.
    auto x2{10}; // Non-compliant - according to C++14 standard the
                 // auto-declared variable is of type std::initializer_list.
                 // However, it can behave differently on different compilers.
    auto x3 = 10; // Compliant - the auto-declared variable is of type int, but
                  // non-compliant with A8-5-2.
    auto x4 = {10}; // Non-compliant - the auto-declared variable is of type
                    // std::initializer_list, non-compliant with A8-5-2.
    std::int8_t x5{10}; // Compliant
}

See also

Effective Modern C++ [13]: Item 2. Understand auto type deduction.

Effective Modern C++ [13]: Item 7. Distinguish between () and {} when creating objects.

Rule A8-5-4 (advisory, implementation, automated)

If a class has a user-declared constructor that takes a parameter of type std::initializer_list, then it shall be the only constructor apart from special member function constructors.

Rationale

If an object is initialized using {} braced-initialization, the compiler strongly prefers constructor taking parameter of type std::initializer_list to other constructors. Thus, if it is defined in the class, it is initially a sole member of the candidate set of the two-phase overload resolution. Only if no viable std::initializer_list is found, the rest of constructors are considered in the second overload resolution. Such a case can be non-intuitive for developers and can lead to reviewers’ confusion on which constructor was intended to be called. If other constructors (besides the std::initializer_list one and special member functions) are declared in a class, then it is suggested to use, e.g. the std::vector( {1,1} ) syntax instead of std::vector v{1, 1}, which makes the intent clear.

Example

// $Id: A8-5-4.cpp 319328 2018-05-15 10:30:25Z michal.szczepankiewicz $
#include <cstdint>
#include <initializer_list>
#include <vector>

#include <iostream>

//non-compliant, there are other constructors
//apart from initializer_list one defined
class A
{
public:
A() = default;
A(std::size_t num1, std::size_t num2) : x{num1}, y{num2} {}
A(std::initializer_list<std::size_t> list) : x{list.size()}, y{list.size()} {
}
private:
std::size_t x;
std::size_t y;
};

class B
{
public:
B() = default;
B(std::initializer_list<std::size_t> list) : collection{list} { }

private:
std::vector<std::size_t> collection;

};

void F1() noexcept
{
A a1{};
A a2{{}};
A a3{0, 1};
recommended
A a4({0, 1});//
A a5(0, 1); //
by exception
}
void F2() noexcept
{
B b1{};
B b2{{}};
B b3{1, 2};
recommended
B b4({1, 2});
recommended
}

// Calls A::A()
// Calls A::A(std::initializer_list<std::size_t>)
// Calls A::A(std::initializer_list<std::size_t>), not
Calls A::A(std::initializer_list<std::size_t>), recommended
Calls A::A(std::size_t, std::size_t), compliant with A8-5-2

// Calls B::B()
// Calls B::B(std::initializer_list<std::size_t>)
// Calls B::B(std::initializer_list<std::size_t>), not
// Calls B::B(std::initializer_list<std::size_t>),

See also

Effective Modern C++ [13]: Item 7. Distinguish between () and {} when creating objects. ISO/IEC 14882:2014 [3]: 13.3.1.7: [over.match.list]

Rule M9-3-1 (required, implementation, automated)

Const member functions shall not return non-const pointers or references to class-data. See MISRA C++ 2008 [7] Note: This rule applies to smart pointers, too. Note: “The class-data for a class is all non-static member data and any resources acquired in the constructor or released in the destructor.” [MISRA C++ 2008 [7]]

Rule A9-3-1 (required, implementation, partially automated)

Member functions shall not return non-const “raw” pointers or references to private or protected data owned by the class.

Rationale

By implementing class interfaces with member functions the implementation retains more control over how the object state can be modified and helps to allow a class to be maintained without affecting clients. Returning a handle to data that is owned by the class allows for clients to modify the state of the object without using an interface. Note that this rule applies to data that are owned by the class (i.e. are class-data). Nonconst handles to objects that are shared between different classes may be returned.

See: Ownership.

Exception

Classes that mimic smart pointers and containers do not violate this rule.

Example

// $Id: A9-3-1.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <cstdint>
#include <memory>
#include <utility>
class A
{
public:
explicit A(std::int32_t number) : x(number) {}
// Implementation
std::int32_t&
GetX() noexcept // Non-compliant - x is a resource owned by the A class
{
return x;
}

private:
std::int32_t x;
};
void Fn1() noexcept
{
A a{10};
std::int32_t& number = a.GetX();
number = 15; // External modification of private class data
}
class B
{
public:
explicit B(std::shared_ptr<std::int32_t> ptr) : sharedptr(std::move(ptr)) {}
// Implementation
std::shared_ptr<std::int32_t> GetSharedPtr() const

noexcept // Compliant - sharedptr is a variable being shared between
// instances

{

return sharedptr;

}

private:
std::shared_ptr<std::int32_t> sharedptr;

};
void Fn2() noexcept
{
std::shared_ptr<std::int32_t> ptr = std::make_shared<std::int32_t>(10);
B b1{ptr};
B b2{ptr};

*ptr = 50; // External modification of ptr which shared between b1 and b2

// instances
auto shared = b1.GetSharedPtr();

*shared = 100; // External modification of ptr which shared between b1 and

// b2 instances
}
class C
{
public:
explicit C(std::int32_t number)
: ownedptr{std::make_unique<std::int32_t>(number)}
{
}
// Implementation
const std::unique_ptr<std::int32_t>& GetOwnedPtr() const
noexcept // Non-compliant - only unique_ptr is const, the object that
// it is pointing to is modifiable
{
return ownedptr;
}
const std::int32_t& GetData() const noexcept // Compliant
{

return *ownedptr;

}

private:
std::unique_ptr<std::int32_t> ownedptr;

};
void Fn3() noexcept
{
C c{10};
const std::int32_t& data = c.GetData();
// data = 20; // Can not modify data, it is a const reference
const std::unique_ptr<std::int32_t>& ptr = c.GetOwnedPtr();

*ptr = 20; // Internal data of class C modified

}

See also

MISRA C++ 2008 [7]: Rule 9-3-2 Member functions shall not return non-const handles to class-data. JSF December 2005 [8]: AV Rule 112: Function return values should not obscure resource ownership.

Rule M9-3-3 (required, implementation, automated)

If a member function can be made static then it shall be made static, otherwise if it can be made const then it shall be made const. See MISRA C++ 2008 [7] Note: Static methods can only modify static members of a class, they are not able to access data of a class instance. Note: Const methods can only modify static members of a class or mutable-declared members of a class instance.


## See also
C++ Core Guidelines [11]: Con.2: By default, make member functions const.

Rule A9-5-1 (required, implementation, automated)

Unions shall not be used.

Rationale

Unions are not type safe and their usage can be misleading and easily misinterpreted by developers.

Exception

It is allowed to use tagged unions until std::variant is available in the C++ Standard Library (C++17)

Example

// $Id: A9-5-1.cpp 305588 2018-01-29 11:07:35Z michal.szczepankiewicz $

#include <cstdint>
// Compliant
struct Tagged
{
enum class TYPE

{

UINT,
FLOAT

};
union {
uint32_t u;
float f;
};
TYPE which;

};

int main(void)
{
Tagged un;

un.u = 12;
un.which = Tagged::TYPE::UINT;

un.u = 3.14f;
un.which = Tagged::TYPE::FLOAT;

return 0;

}

See also

MISRA C++ 2008 [7]: M9-5-1: Unions shall not be used JSF December 2005 [8]: AV Rule 153: Bit-fields shall have explicitly unsigned integral or enumeration types only C++ Core Guidelines [11]: C.181: Avoid “naked” unions C++ Core Guidelines [11]: C.182: Use anonymous unions to implement tagged unions C++ Core Guidelines [11]: Type.7: Avoid naked union: Use variant instead.

Rule M9-6-1 (required, implementation, non-automated)

When the absolute positioning of bits representing a bit-field is required, then the behavior and packing of bit-fields shall be documented. See MISRA C++ 2008 [7]

Rule A9-6-1 (required, design, partially automated)

Data types used for interfacing with hardware or conforming to communication protocols shall be trivial, standard-layout and only contain members of types with defined sizes.

Rationale

When the layout of data types is important, only those types that have a defined size shall be used (see A3-9-1, this excludes bool, wchar_t, pointers, and pointers to members). Enumeration types may be used if they have been explicitly declared with an underlying type that has a defined size. Note: As the use of bit-fields is only allowed for interfacing with hardware or conforming to communication protocols, this restriction on types also applies to bitfields, see A9-6-2. Note: The signed exact-width integer types like std::int16_t are guaranteed to have a two’s complement representation.

Example

// $Id: A9-6-1.cpp 319312 2018-05-15 08:29:17Z christof.meerwald $
#include <cstdint>

enum class E1 : std::uint8_t
{
E11,
E12,
E13
};
enum class E2 : std::int16_t
{
E21,
E22,
E23
};
enum class E3
{
E31,
E32,
E33
};
enum E4
{
E41,
E42,
E43
};

class C
{

public:
std::int32_t a : 2;
std::uint8_t b : 2U;

// Compliant
// Compliant

bool c : 1;

// Non-compliant - the size of bool is implementation defined

char d : 2;
// Non-compliant
wchar_t e : 2; // Non-compliant - the size of wchar_t is implementation defined

E1 f1
: 2;
// Compliant
E2 f2
: 2;
// Compliant
E3 f3 : 2;// Non-compliant - E3 enum class does not explicitly define
// underlying type
E4 f4 : 2; // Non-compliant - E4 enum does not explicitly define underlying
// type

};

struct D
{
std::int8_t a;

// Compliant

bool b;

// Non-compliant - the size of bool is
// implementation defined

std::uint16_t c1
std::uint16_t c2

: 8;
: 8;

// Compliant
// Compliant

};

void Fn() noexcept
{
C c;
c.f1 = E1::E11;
}

See also

MISRA C++ 2008 [7]: A9-6-2: Bit-fields shall be either bool type or an explicitly unsigned or signed integral type JSF December 2005 [8]: AV Rule 154: Bit-fields shall have explicitly unsigned integral or enumeration types only HIC++ v4.0 [9]: 9.2.1: Declare bit-fields with an explicitly unsigned integral or enumeration type Rule A9-6-2 (required, design, non-automated) Bit-fields shall be used only when interfacing to hardware or conforming to communication protocols.

Rationale

Usage of bit-fields increases code complexity and certain aspects of bit-field manipulation can be error prone and implementation-defined. Hence a bit-field usage is reserved only when interfacing to hardware or conformance to communication protocols Note: A9-6-1 restricts the types allowed to be used in these contexts.


## See also
JSF December 2005 [8]: AV Rule 155: Bit-fields will not be used to pack data
into a word for the sole purpose of saving space.

Rule M9-6-4 (required, implementation, automated)

Named bit-fields with signed integer type shall have a length of more than one bit. See MISRA C++ 2008 [7] Note: The signed exact-width integer types like std::int16_t are guaranteed to have a two’s complement representation (see also A9-6-1). In this case, a single bit signed bit-field contains only a sign bit, thus it can represent values either (-1) or (0). Therefore, to avoid developers’ confusion, it is recommended to use unsigned types for single bit bit-fields.

Rule A10-0-1 (required, design, non-automated)

Public inheritance shall be used to implement “is-a” relationship.

Rationale

Public and non-public inheritance have a very different application and it shall be used accordingly. See: Is-a-relationship, Has-a-relationship


## See also
JSF December 2005 [8]: AV Rule 91: Public inheritance will be used to
implement “is-a” relationships.

Rule A10-0-2 (required, design, non-automated)

Membership or non-public inheritance shall be used to implement “hasa” relationship.

Rationale

Public and non-public inheritance have a very different application and it shall be used accordingly. See: Is-a-relationship, Has-a-relationship


## See also
JSF December 2005 [8]: AV Rule 93: “has-a” or “is-implemented-in-terms-of”
relationships will be modeled through membership or non-public inheritance.

Rule A10-1-1 (required, implementation, automated)

Class shall not be derived from more than one base class which is not an interface class.

Rationale

Multiple inheritance exposes derived class to multiple implementations. This makes the code more difficult to maintain. See: Diamond-Problem, Interface-Class

Example

// $Id: A10-1-1.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <cstdint>
class A
{
public:
void F1() noexcept(false) {}

private:
std::int32_t x{0};
std::int32_t y{0};
};
class B
{
public:
void F2() noexcept(false) {}

private:

std::int32_t x{0};
};
class C : public A,
public B // Non-compliant - A and B are both not interface classes
{
};
class D
{
public:
virtual ~D() = 0;
virtual void F3() noexcept = 0;
virtual void F4() noexcept = 0;
};
class E
{
public:
static constexpr std::int32_t value{10};

virtual ~E() = 0;
virtual void F5() noexcept = 0;
};
class F : public A,
public B,
public D,
public E // Non-compliant - A and B are both not interface classes
{
};
class G : public A,
public D,
public E // Compliant - D and E are interface classes
{
};

See also

JSF December 2005 [8]: AV Rule 88 Multiple inheritance shall only be allowed in the following restricted form: n interfaces plus m private implementations, plus at most one protected implementation. HIC++ v4.0 [9]: 10.3.1 Ensure that a derived class has at most one base class which is not an interface class. C++ Core Guidelines [11]: C.135: Use multiple inheritance to represent multiple distinct interfaces.

Rule M10-1-1 (advisory, implementation, automated)

Classes should not be derived from virtual bases. See MISRA C++ 2008 [7]

Rule M10-1-2 (required, implementation, automated)

A base class shall only be declared virtual if it is used in a diamond hierarchy. See MISRA C++ 2008 [7]

Rule M10-1-3 (required, implementation, automated)

An accessible base class shall not be both virtual and non-virtual in the same hierarchy. See MISRA C++ 2008 [7]

Rule M10-2-1 (advisory, implementation, automated)

All accessible entity names within a multiple inheritance hierarchy should be unique. See MISRA C++ 2008 [7] Rule A10-2-1 (required, implementation, automated) Non-virtual public or protected member functions shall not be redefined in derived classes.

Rationale

A non-virtual member function specifies an invariant over the hierarchy. It cannot be overridden in derived classes, but it can be hidden by a derived class member (data or function) with the same identifier. The effect of this hiding is to defeat polymorphism by causing an object to behave differently depending on which interface is used to manipulate it, resulting in unnecessary complexity and error. Note that a maintenance change to a private implementation detail could impact clients of the base class, and often it will be the case that those clients may not be in a position to fix the problem. Therefore, redefinitions of functions which are private in the base class are not affected by this rule.

Exception

Redefinition of functions from private inheritance do not violate this rule.

Example

// $Id: A10-2-1.cpp 317123 2018-04-23 08:48:11Z ilya.burylov $
class A
{
public:
virtual ~A() = default;
void F() noexcept {}
virtual void G() noexcept {}
private:
void H() noexcept {}
};
class B : public A
{
public:
void
F() noexcept {} // Non-compliant - F() function from A class hidden by B class
void G() noexcept override {} // Compliant - G() function from A class
// overridden by B class
private:
void H() noexcept {} // Compliant - H() function is private in A class
};
class C : private A
{
public:
F() noexcept {} // Compliant by exception - private inheritance
};
void Fn1(A& object) noexcept
{
object.F(); // Calls F() function from A
object.G(); // Calls G() function from B
}
void Fn2() noexcept
{
B b;
Fn1(b);
}

See also

JSF December 2005 [8]: AV Rule 94 An inherited nonvirtual function shall not be redefined in a derived class. C++ Core Guidelines [11]: ES.12: Do not reuse names in nested scopes.

Rule A10-3-1 (required, implementation, automated)

Virtual function declaration shall contain exactly one of the three specifiers: (1) virtual, (2) override, (3) final.

Rationale

Specifying more than one of these three specifiers along with virtual function declaration is redundant and a potential source of errors. It is recommended to use the virtual specifier only for new virtual function declaration, the override specifier for overrider declaration, and the final specifier for final overrider declaration. Note that this applies to virtual destructors and virtual operators, too.

Example

// $Id: A10-3-1.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
class A
{
public:
virtual
~A() {}
// Compliant
virtual
void F() noexcept = 0;
// Compliant
virtual void G() noexcept final = 0; // Non-compliant - virtual final pure
// function is redundant
virtual void
H() noexcept final // Non-compliant - function is virtual and final
{
}
virtual void K() noexcept // Compliant
{
}
virtual void J() noexcept {}
virtual void M() noexcept // Compliant
{
}
virtual void Z() noexcept // Compliant
{
}
virtual A& operator+=(A const& rhs) noexcept // Compliant
{
// ...
return *this;

}
};
class B : public A
{
public:
~B() override {}
// Compliant
virtual void F() noexcept override // Non-compliant - function is specified
// with virtual and override

{
}
void K() noexcept override
final // Non-compliant - function is specified with override and final
{
}
virtual void M() noexcept // Compliant - violates A10-3-2
{
}
void Z() noexcept override // Compliant
{
}
void J() noexcept // Non-compliant - virtual function but not marked as
// overrider
{
}
A& operator+=(A const& rhs) noexcept override // Compliant - to override
// the operator correctly,
// its
signature needs to be
// the same as in the base
// class
{
// ...

return *this;

}

};

See also

C++ Core Guidelines [11]: C.128: Virtual functions should specify exactly one of virtual, override, or final.

Rule A10-3-2 (required, implementation, automated)

Each overriding virtual function shall be declared with the override or final specifier.

Rationale

Explicit use of the override or final specifier enables the compiler to catch mismatch of types and names between base and derived classes virtual functions. Note that this rule applies to virtual destructor overriders, too. Also, note that this rule applies to a pure virtual function which overrides another pure virtual function.

Example

// $Id: A10-3-2.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
class A
{

public:
virtual ~A() {}
virtual void F() noexcept = 0;
virtual void G() noexcept {}
virtual void Z() noexcept {}
virtual A& operator+=(A const& oth) = 0;

};
class B : public A
{
public:
~B() override {}
// Compliant
void F() noexcept // Non-compliant
{
}
virtual void G() noexcept // Non-compliant
{
}
void Z() noexcept override // Compliant
{
}
B& operator+=(A const& oth) override // Compliant
{
return *this;

}

};
class C : public A
{
public:
~C() {}
// Non-compliant
void F() noexcept override // Compliant
{
}
void G() noexcept override // Compliant
{
}
void Z() noexcept override // Compliant
{
}
C& operator+=(A const& oth) // Non-compliant
{
return *this;

}

};

See also

HIC++ v4.0 [9]: 10.2.1 Use the override special identifier when overriding a virtual function C++ Core Guidelines [11]: C.128: Virtual functions should specify exactly one of virtual, override, or final.

Rule A10-3-3 (required, implementation, automated)

Virtual functions shall not be introduced in a final class.

Rationale

Declaring a class as final explicitly specifies that the class cannot be inherited. Declaring a virtual function inside a class specifies that the function can be overridden in the inherited class, which is inconsistent.

Example

// $Id: A10-3-3.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
class A
{
public:
virtual ~A() = default;
virtual void F() noexcept = 0;
virtual void G() noexcept {}
};
class B final : public A
{
public:
void F() noexcept final // Compliant
{
}
void G() noexcept override // Non-compliant
{
}
virtual void H() noexcept = 0; // Non-compliant
virtual void Z() noexcept
// Non-compliant
{
}
};

See also

HIC++ v4.0 [9]: 9.1.5 Do not introduce virtual functions in a final class.

Rule A10-3-5 (required, implementation, automated)

A user-defined assignment operator shall not be virtual.

Rationale

If an overloaded operator is declared virtual in a base class A, then in its subclasses B and C identical arguments list needs to be provided for the overriders. This allows to call an assignment operator of class B that takes an argument of type C which may lead to undefined behavior. Note that this rule applies to all assignment operators, as well to copy and move assignment operators.

Example

// $Id: A10-3-4.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
class A
{
public:
virtual A& operator=(A const& oth) = 0;
// Non-compliant
virtual A& operator+=(A const& rhs) = 0; // Non-compliant
};
class B : public A
{
public:
B& operator=(A const& oth) override // It needs to take an argument of type
// A& in order to override
{
return *this;

}
B& operator+=(A const& oth) override // It needs to take an argument of
// type A& in order to override
{
return *this;

}
B& operator-=(B const& oth) // Compliant
{
return *this;

}
};
class C : public A
{
public:
C& operator=(A const& oth) override // It needs to take an argument of type
// A& in order to override
{
return *this;

}
C& operator+=(A const& oth) override // It needs to take an argument of
// type A& in order to override
{
return *this;

}
C& operator-=(C const& oth) // Compliant
{
return *this;

}
};
// class D : public A
//{
// public:
//D& operator=(D const& oth) override // Compile time error - this method
//does not override because of different
//
signature
//
{

return *this;
//
//
}
//D& operator+=(D const& oth) override // Compile time error - this method
//does not override because of different
//
signature
//
{
return *this;
//
//
}
//};
void Fn() noexcept
{
B b;
C c;
b = c;
// Calls B::operator= and accepts an argument of type C
b += c; // Calls B::operator+= and accepts an argument of type C
c = b;
// Calls C::operator= and accepts an argument of type B
c += b; // Calls C::operator+= and accepts an argument of type B
// b -= c; // Compilation error, because of types mismatch. Expected
// behavior
// c -= b; // Compilation error, because of types mismatch. Expected
// behavior

B b2;
C c2;
b -= b2;
c -= c2;

}

See also

none

Rule M10-3-3 (required, implementation, automated)

A virtual function shall only be overridden by a pure virtual function if it is itself declared as pure virtual. See MISRA C++ 2008 [7] See: A10-3-2 for pure virtual function overriders declaration.

Rule A10-4-1 (advisory, design, non-automated)

Hierarchies should be based on interface classes.

Rationale

Software design that provides common and standardized interfaces without committing to a particular implementation:

eliminates of potential redundancy. increases software reusability. hides implementation details. can be easily extended.

facilitates different objects iteration. Well-defined interfaces are less prone to require further reworking and maintenance. See: Interface-Class


## See also
JSF December 2005 [8]: AV Rule 87: Hierarchies should be based on abstract
classes.
C++ Core Guidelines [11]: I.25: Prefer abstract classes as interfaces to class
hierarchies.
C++ Core Guidelines [11]: C.122: Use abstract classes as interfaces when
complete separation of interface and implementation is needed.

Rule M11-0-1 (required, implementation, automated)

Member data in non-POD class types shall be private.

See MISRA C++ 2008 [7] See: POD-type, Standard-Layout-Class, Trivially-Copyable

Rule A11-0-1 (advisory, implementation, automated)

A non-POD type should be defined as class.

Rationale

Types that are not POD types are supposed to be defined as class objects, as a class specifier forces the type to provide private access control for all its members by default. This is consistent with developer expectations, because it is expected that a class has its invariant, interface and could provide custom-defined constructors.

Example

// $Id: A11-0-1.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <cstdint>
#include <limits>
class A // Compliant - A provides user-defined constructors, invariant and
// interface
{
std::int32_t x; // Data member is private by default

public:
static constexpr std::int32_t maxValue =
std::numeric_limits<std::int32_t>::max();
A() : x(maxValue) {}
explicit A(std::int32_t number) : x(number) {}
A(A const&) = default;
A(A&&) = default;
A& operator=(A const&) = default;
A& operator=(A&&) = default;

std::int32_t GetX() const noexcept { return x; }
void SetX(std::int32_t number) noexcept { x = number; }
};
struct B // Non-compliant - non-POD type defined as struct
{
public:
static constexpr std::int32_t maxValue =
std::numeric_limits<std::int32_t>::max();
B() : x(maxValue) {}
explicit B(std::int32_t number) : x(number) {}
B(B const&) = default;
B(B&&) = default;
B& operator=(B const&) = default;
B& operator=(B&&) = default;

std::int32_t GetX() const noexcept { return x; }
void SetX(std::int32_t number) noexcept { x = number; }

private:
std::int32_t x; // Need to provide private access specifier for x member
};
struct C // Compliant - POD type defined as struct
{
std::int32_t x;
std::int32_t y;
};
class D // Compliant - POD type defined as class, but not compliant with
// M11-0-1
{
public:
std::int32_t x;
std::int32_t y;
};

See also

C++ Core Guidelines [11]: C.2: Use class if the class has an invariant; use struct if the data members can vary independently. stackoverflow.com [17]: When should you use a class vs a struct in C++?

Rule A11-0-2 (required, implementation, automated)

A type defined as struct shall: (1) provide only public data members, (2) not provide any special member functions or methods, (3) not be a base of another struct or class, (4) not inherit from another struct or class.

Rationale

This is consistent with developer expectations that a class provides its invariant, interface and encapsulation guarantee, while a struct is only an aggregate without any class-like features. An example of a struct type is POD type. See: POD-type.

Example

// $Id: A11-0-2.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <cstdint>
struct A // Compliant
{
std::int32_t x;
double y;
};
struct B // Compliant
{
std::uint8_t x;
A a;
};
struct C // Compliant
{
float x = 0.0f;
std::int32_t y = 0;
std::uint8_t z = 0U;
};
struct D // Non-compliant
{
public:
std::int32_t x;

protected:
std::int32_t y;

private:

std::int32_t z;
};
struct E // Non-compliant
{
public:
std::int32_t x;
void Fn() noexcept {}

private:
void F1() noexcept(false) {}
};
struct F : public D // Non-compliant
{
};

See also

stackoverflow.com [17]: When should you use a class vs a struct in C++?

Rule A11-3-1 (required, implementation, automated)

Friend declarations shall not be used.

Rationale

Friend declarations reduce encapsulation and result in code that is more difficult to maintain.

Exception

It is allowed to declare comparison operators as friend functions, see A13-5-5.

Example

// $Id: A11-3-1.cpp 325916 2018-07-13 12:26:22Z christof.meerwald $
class A
{
public:
A& operator+=(A const& oth);
friend A const operator+(A const& lhs, A const& rhs); // Non-compliant
};
class B
{
public:
B& operator+=(B const& oth);
friend bool operator ==(B const& lhs, B const& rhs) // Compliant by exception
{

// Implementation

}

};

B const operator+(B const& lhs, B const& rhs) // Compliant
{
// Implementation
}

See also

JSF December 2005 [8]: AV Rule 70 A class will have friends only when a function or object requires access to the private elements of the class, but is unable to be a member of the class for logical or efficiency reasons. HIC++ v4.0 [9]: 11.2.1 Do not use friend declarations.

Rule A12-0-1 (required, implementation, automated)

If a class declares a copy or move operation, or a destructor, either via “=default”, “=delete”, or via a user-provided declaration, then all others of these five special member functions shall be declared as well.

Rationale

The semantics of five of the special member functions, the copy constructor, the move constructor,

the copy assignment operator, the

move

assignment

operator, and the destructor, are closely related to each other. If, for example, there is need to provide a nondefault destructor to release a resource, special handling usually also needs to be added in the copy and move operations to properly handle this resource. Language rules exist to generate the special member functions under certain conditions. For historical reasons, these language rules are not entirely consistent. For example, the presence of a destructor does not prevent the compiler from generating copy operations. However, it prevents the move operations from being generated. Thus

it is required, in order to maintain consistency and document the programmer’s intent, that either none or all of the five functions are declared. This rule is also known as “the rule of zero”, or “the rule of five” respectively. It is highly recommended to design classes in a way that the rule of zero can be followed. Note that the default constructor (which is also a special member function) is not part of this rule. The presence of any user-declared constructor inhibits the generation of the default constructor. Therefore, if a user-declared constructor is present, it may be necessary (depending on requirements) to also declare the default constructor. However, the presence of a user-declared default constructor does not inhibit the generation of the other five special member functions. This rule therefore allows to follow the rule of zero when the class only has a user-declared default constructor (and possibly one or more constructors which are not special member functions).

Example

// $Id: A12-0-1.cpp 309769 2018-03-01 17:40:29Z jan.babst $
#include <string>

namespace v1
{
// Class is copyable and moveable via the compiler generated funtions.
// Compliant - rule of zero.
class A
{
private:
// Member data ...
};
} // namespace v1

namespace v2
{
// New requirement: Destructor needs to be added.
// Now the class is no longer moveable, but still copyable. The program
// still compiles, but may perform worse.
// Non-compliant - Unclear if this was the developers intent.
class A
{
public:
~A()
{
// ...
}

private:
// Member data ...
};
} // namespace v2

namespace v3
{

// Move operations are brought back by defaulting them.
// Copy operations are defaulted since they are no longer generated
// (complies to A12-0-1 but will also be a compiler error if they are needed).
// Default constructor is defaulted since it is no longer generated
// (not required by A12-0-1 but will be a compiler error if it is needed).
// Compliant - rule of five. Programmer’s intent is clear, class behaves the
// same as v1::A.
class A
{
public:
A() = default;
A(A const&) = default;
A(A&&) = default;
~A()
{
// ...
}
A& operator=(A const&) = default;
A& operator=(A&&) = default;

private:
// Member data ...

};
} // namespace v3

// A class with regular (value) semantics.
// Compliant - rule of zero.
class Simple
{
public:
// User defined constructor, also acts as default constructor.
explicit Simple(double d = 0.0, std::string s = "Hello")
: d_(d), s_(std::move(s))
{
}

// Compiler generated copy c’tor, move c’tor, d’tor, copy assignment, move
// assignment.

private:
double d_;
std::string s_;

};

// A base class.
// Compliant - rule of five.
class Base
{
public:
Base(Base const&) = delete;
Base(Base&&) = delete;

// see also
// see also

A12-8-6
A12-8-6

virtual ~Base() = default;
// see also A12-4-1
Base& operator=(Base const&) = delete; // see also A12-8-6
Base& operator=(Base&&) = delete;
// see also A12-8-6

// Declarations of pure virtual functions ...

protected:
Base() = default; // in order to allow construction of derived objects

};

// A move-only class.
// Compliant - rule of five.
class MoveOnly
{
public:
MoveOnly();
MoveOnly(MoveOnly const&) = delete;
MoveOnly(MoveOnly&&) noexcept;
~MoveOnly();
MoveOnly& operator=(MoveOnly const&) = delete;
MoveOnly& operator=(MoveOnly&&) noexcept;

private:
// ...

};

See also

C++ Core Guidelines [11]: C.21: If you define or =delete any default operation, define or =delete them all. C++ Core Guidelines [11]: C.81: Use =delete when you want to disable default behavior (without wanting an alternative).

Rule A12-0-2 (required, implementation, partially automated)

Bitwise operations and operations that assume data representation in memory shall not be performed on objects.

Rationale

Object representations may consist of more than only the declared fields (unless the objects are standard-layout or trivially copyable). Performing bitwise operations on objects may access bits that are not part of the value representation, which may lead to undefined behavior. Operations on objects (e.g. initialization, copying, comparing, setting, accessing) shall be done by dedicated constructors, overloaded operators, accessors or mutators.

Example

// $Id: A12-0-2.cpp 305629 2018-01-29 13:29:25Z piotr.serwa $

//
#include <cstdint>
#include <cstring>

class A
{
public:
A() = default;
A(uint8_t c, uint32_t i, int8_t d, int32_t h) : c(c), i(i), d(d), h(h) {}

bool operator==(const A& rhs) const noexcept
{
return c==rhs.c && i==rhs.i && d==rhs.d && h==rhs.h;
}

private:
uint8_t c;
uint32_t i;
int8_t d;
int32_t h;
};

int main(void)
{
A noninit;

//setting field c
std::memset(&noninit, 3, 1); //non-compliant
//setting field i

std::memset(((uint8_t*)&noninit)+sizeof(uint8_t)+3, 5, 1); //non-compliant

A init(3, 5, 7, 9); //compliant

if (noninit == init) //compliant
{

}

if (0 == std::memcmp(&noninit, &init, sizeof(init)))
{ //non-compliant, includes padding bytes

}

return 0;

}

See also

JSF December 2005 [8]: AV Rule 156: All the members of a structure (or class) shall be named and shall only be accessed via their names.

JSF December 2005 [8]: AV Rule 210: Algorithms shall not make assumptions concerning how data is represented in memory (e.g. big endian vs. little endian, base class subobject ordering in derived classes, nonstatic data member ordering across access specifiers, etc.) JSF December 2005 [8]: AV Rule 210.1: Algorithms shall not make assumptions concerning the order of allocation of nonstatic data members separated by an access specifier. JSF December 2005 [8]: AV Rule 211: Algorithms shall not assume that shorts, ints, longs, floats, doubles or long doubles begin at particular addresses. SEI CERT C++ Coding Standard [10]: EXP42-C: Do not compare padding data SEI CERT C++ Coding Standard [10]: EXP62-C: Do not access the bits of an object representation that are not part of the object’s value representation SEI CERT C++ Coding Standard [10]: OOP57-CPP: Prefer special member functions and overloaded operators to C Standard Library functions

Rule A12-1-1 (required, implementation, automated)

Constructors shall explicitly initialize all virtual base classes, all direct non-virtual base classes and all non-static data members.

Rationale

A constructor of a class is supposed to completely initialize its object. Explicit initialization of all virtual base classes, direct non-virtual base classes and non-static data members reduces the risk of an invalid state after successful construction.

Example

// $Id: A12-1-1.cpp 271696 2017-03-23 09:23:09Z piotr.tanski $
#include <cstdint>
class Base
{
// Implementation
};
class VirtualBase
{
};
class A : public virtual VirtualBase, public Base
{
public:
A() : VirtualBase{}, Base{}, i{0}, j{0} // Compliant
{
}

A(A const& oth)
: Base{}, j{0}

//
//

Non-compliant - VirtualBase base class and member
i not initialized

{
}

private:
std::int32_t i;
std::int32_t j;
static std::int32_t k;
};
std::int32_t A::k{0};

See also

MISRA C++ 2008 [7]: Rule 12-1-2 All constructors of a class should explicitly call a constructor for all of its immediate base classes and all virtual base classes.

HIC++ v4.0 [9]:12.4.2 Ensure that a constructor initializes explicitly all base classes and non-static data members. JSF December 2005 [8]: AV Rule 71: Calls to an externally visible operation of an object, other than its constructors, shall not be allowed until the object has been fully initialized.

Rule M12-1-1 (required, implementation, automated)

An object’s dynamic type shall not be used from the body of its constructor or destructor. See MISRA C++ 2008 [7] Note: This rule prohibits both direct and indirect usage of object’s dynamic type from its constructor or destructor.


## See also
C++ Core Guidelines [11]: C.50: Use a factory function if you need “virtual
behavior” during initialization.

Rule A12-1-2 (required, implementation, automated)

Both NSDMI and a non-static member initializer in a constructor shall not be used in the same type.

Rationale

Since 2011 C++ Language Standard it is allowed to initialize a non-static member along with the declaration of the member in the class body using NSDMI (“non-static data member initializer”). To avoid possible confusion which values are actually used,

if any member is initialized by NSDMI or with a constructor, then all others should be initialized the same way.

Exception

The move and copy constructors are exempt from this rule, because these constructors copy the existing values from other objects.

Example

// $Id: A12-1-2.cpp 271696 2017-03-23 09:23:09Z piotr.tanski $
#include <cstdint>
#include <utility>
class A
{
public:
A() : i1{0}, i2{0} // Compliant - i1 and i2 are initialized by the
// constructor only. Not compliant with A12-1-3
{
}
// Implementation

private:
std::int32_t i1;
std::int32_t i2;
};
class B
{
public:
// Implementation

private:
std::int32_t i1{0};
std::int32_t i2{
0}; // Compliant - both i1 and i2 are initialized by NSDMI only
};
class C
{
public:
C() : i2{0} // Non-compliant - i1 is initialized by NSDMI, i2 is in
// member in member initializer list
{
}
C(C const& oth) : i1{oth.i1}, i2{oth.i2} // Compliant by exception
{
}
C(C&& oth)
: i1{std::move(oth.i1)},
i2{std::move(oth.i2)} // Compliant by exception
{
}
// Implementation

private:
std::int32_t i1{0};
std::int32_t i2;

};

See also

HIC++ v4.0 [9]:12.4.3 Do not specify both an NSDMI and a member initializer in a constructor for the same non static member

Rule A12-1-3 (required, implementation, automated)

If all user-defined constructors of a class initialize data members with constant values that are the same across all constructors, then data members shall be initialized using NSDMI instead.

Rationale

Using NSDMI lets the compiler to generate the function that can be more efficient than a user-defined constructor that initializes data member variables with predefined constant values.

Example

// $Id: A12-1-3.cpp 291949 2017-10-19 21:26:22Z michal.szczepankiewicz $
#include <cstdint>
#include <string>
class A
{
public:
A() : x(0), y(0.0F), str() // Non-compliant
{
}
// ...

private:
std::int32_t x;
float y;
std::string str;

};
class B
{
public:
// ...

private:
std::int32_t x = 0;
// Compliant
float y = 0.0F;
// Compliant
std::string str = ""; // Compliant

};

class C
{
public:
C() : C(0, 0.0F, decltype(str)()) // Compliant
{
}
C(std::int32_t i, float f, std::string s) : x(i), y(f), str(s) // Compliant
{
}
// ...

private:
std::int32_t x =
0;// Non-compliant - there’s a constructor that initializes C
// class with user input
float y = 0.0F; // Non-compliant - there’s a constructor that initializes C
// class with user input
std::string str = ""; // Non-compliant - there’s a constructor that
// initializes C class with user input

};

See also

C++ Core Guidelines [11]: C.45: Don’t define a default constructor that only initializes data members; use in-class member initializers instead.

Rule A12-1-4 (required, implementation, automated)

All constructors that are callable with a single argument of fundamental type shall be declared explicit.

Rationale

The explicit keyword prevents the constructor from being used to implicitly convert a fundamental type to the class type. See: Fundamental-Types.

Example

// $Id: A12-1-4.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <cstdint>
class A
{
public:
explicit A(std::int32_t number) : x(number) {} // Compliant
A(A const&) = default;
A(A&&) = default;
A& operator=(A const&) = default;
A& operator=(A&&) = default;

private:
std::int32_t x;
};
class B
{
public:
B(std::int32_t number) : x(number) {} // Non-compliant
B(B const&) = default;
B(B&&) = default;
B& operator=(B const&) = default;
B& operator=(B&&) = default;

private:
std::int32_t x;
};
void F1(A a) noexcept
{
}
void F2(B b) noexcept
{
}
void F3() noexcept
{
F1(A(10));
// f1(10); // Compilation error - because of explicit constructor it is not
// possible to implicitly convert integer
// to type of class A
F2(B(20));
F2(20); // No compilation error - implicit conversion occurs
}

See also

MISRA C++ 2008 [7]: Rule 12-1-3 (Required) All constructors that are callable with a single argument of fundamental type shall be declared explicit.

Rule A12-1-5 (required, implementation, partially automated)

Common class initialization for non-constant members shall be done by a delegating constructor.

Rationale

Common initialization of non-constant members in a delegating constructor prevents from code repetition, accidental differences and maintenance problems.

Example

// $Id: A12-1-5.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $

#include <cstdint>

class A
{
public:
// Compliant
A(std::int32_t x, std::int32_t y) : x(x + 8), y(y) {}
explicit A(std::int32_t x) : A(x, 0) {}

private:
std::int32_t x;
std::int32_t y;

};

class B
{
public:
// Non-compliant
B(std::int32_t x, std::int32_t y) : x(x + 8), y(y) {}
explicit B(std::int32_t x) : x(x + 8), y(0) {}

private:
std::int32_t x;
std::int32_t y;

};

See also

HIC++ v4.0 [9]: 12.4.5: Use delegating constructors to reduce code duplication. C++ Core Guidelines [11]: C.51: Use delegating constructors to represent common actions for all constructors of a class.

Rule A12-1-6 (required, implementation, automated)

Derived classes that do not need further explicit initialization and require all the constructors from the base class shall use inheriting constructors.

Rationale

Reimplementing constructors that do not need further initialization is error-prone and may lead to using wrong base class constructor accidentally.

Example

// $Id: A12-1-6.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $

#include <cstdint>

class A
{
public:
A(std::int32_t x, std::int32_t y) : x(x + 8), y(y) {}

explicit A(std::int32_t x) : A(x, 0) {}

private:
std::int32_t x;
std::int32_t y;

};

// Non-compliant
class B : public A
{
public:
B(std::int32_t x, std::int32_t y) : A(x, y) {}
explicit B(std::int32_t x) : A(x) {}
};

// Compliant
class C : public A
{
public:
using A::A;
};

See also

C++ Core Guidelines [11]: C.52: Use inheriting constructors to import constructors into a derived class that does not need further explicit initialization.

Rule A12-4-1 (required, implementation, automated)

Destructor of a base class shall be public virtual, public override or protected non-virtual.

Rationale

If an object is supposed to be destroyed through a pointer or reference to its base class, the destructor in the base class needs to be virtual. Otherwise, destructors for derived types will not be invoked. Note that if it is prohibited to destroy an object through a pointer or reference to its base class, the destructor in the base class is supposed to be protected.

Example

// $Id: A12-4-1.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
class A
{
public:
~A() // Non-compliant

{
}

};
class B : public A
{
};
class C
{
public:
virtual ~C() // Compliant
{
}
};
class D : public C
{
};
class E
{
protected:
~E(); // Compliant
};
class F : public E
{
};

void F1(A* obj1, C* obj2)

{
// ...
delete obj1; // Only destructor of class A will be invoked
delete obj2; // Both destructors of D and C will be invoked

}
void F2()
{

A* a = new B;

C* c = new D;

F1(a, c);

}

See also

JSF December 2005 [8]: AV Rule 78 All base classes with a virtual function shall define a virtual destructor. HIC++ v4.0 [9]: 12.2.1 Declare virtual, private or protected the destructor of a type used as a base class. SEI CERT C++ Coding Standard [10]: OOP52-CPP: Do not delete a polymorphic object without a virtual destructor. C++ Core Guidelines [11]: C.35: A base class destructor should be either public and virtual, or protected and nonvirtual.

C++ Core Guidelines [11]: Discussion: Make base class destructors public and virtual, or protected and nonvirtual.

Rule A12-4-2 (advisory, implementation, automated)

If a public destructor of a class is non-virtual, then the class should be declared final.

Rationale

If a public destructor of a class is non-virtual (i.e. no virtual, override or final keyword), then the class is not supposed to be used as a base class in inheritance hierarchy.

Note that a destructor needs to be virtual in a base class in order to correctly destroy an instance of a derived class through a pointer to the base class.

Example

// $Id: A12-4-2.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
class A // Non-compliant - class A should not be used as a base class because
// its destructor is not virtual, but it is
// not declared final
{
public:
A() = default;
A(A const&) = default;
A(A&&) = default;
A& operator=(A const&) = default;
A& operator=(A&&) = default;
~A() = default; // Public non-virtual destructor
};
class B final // Compliant - class B can not be used as a base class, because
// it is declared final, and
it should not be derived
// because its destructor is
not virtual
{
public:
B() = default;
B(B const&) = default;
B(B&&) = default;
B& operator=(B const&) = default;
B& operator=(B&&) = default;
~B() = default; // Public non-virtual destructor
};
class C // Compliant - class C is not final, and its destructor is virtual. It
// can be used as a base class
{
public:
C() = default;
C(C const&) = default;
C(C&&) = default;
C& operator=(C const&) = default;
C& operator=(C&&) = default;

virtual ~C() = default; // Public virtual destructor
};
class AA : public A
{
};
// class BA : public B // Compilation error - can not derive from final base
// class B
//{
//};
class CA : public C
{
};
void Fn() noexcept
{
AA obj1;
CA obj2;
A& ref1 = obj1;
C& ref2 = obj2;

ref1.~A(); // Calls A::~A() only
ref2.~C(); // Calls both CA::~CA() and C::~C()

}

See also

SEI CERT C++ Coding Standard [10]: OOP52-CPP: Do not delete a polymorphic object without a virtual destructor.

Rule A12-6-1 (required, implementation, automated)

All class data members that are initialized by the constructor shall be initialized using member initializers.

Rationale

Using the constructor’s member initializers is more efficient than assigning a copy of passed values to data members in the constructor’s body. Also, it supports the programmer to prevent “data usage before initialization” errors. Note that if a data member is already initialized using member initializer, then changing its value in the constructor’s body does not violate this rule.

Example

// $Id: A12-6-1.cpp 271696 2017-03-23 09:23:09Z piotr.tanski $
#include <cstdint>
#include <string>
class A

{
public:
A(std::int32_t n, std::string s) : number{n}, str{s} // Compliant
{
}
// Implementation

private:
std::int32_t number;
std::string str;

};
class B
{
public:
B(std::int32_t n, std::string s) // Non-compliant - no member initializers
{
number = n;
str = s;
}
// Implementation

private:
std::int32_t number;
std::string str;

};
class C
{
public:
C(std::int32_t n, std::string s) : number{n}, str{s} // Compliant
{
n += 1; // This does not violate the rule
str.erase(str.begin(),
str.begin() + 1);
// This does not violate the rule
}
// Implementation

private:
std::int32_t number;
std::string str;

};

See also

C++ Core Guidelines [11]: C.49: Prefer initialization to assignment in constructors.

Rule A12-7-1 (required, implementation, automated)

If the behavior of a user-defined special member function is identical to implicitly defined special member function, then it shall be defined “=default” or be left undefined.

Rationale

If a user-defined version of a special member function is the same as would be provided by the compiler, it will be less error prone and more maintainable to replace it with “=default” definition or leave it undefined to let the compiler define it implicitly. Note that this rule applies to all special member functions of a class. See: Implicitly-Defined-Default-Constructor, Implicitly-DefinedCopy-Constructor, Implicitly-Defined-Move-Constructor, Implicitly-Defined-Copy-Assignment-Operator, Implicitly-Defined-Move-AssignmentOperator, Implicitly-Defined-Destructor

Example

// $Id: A12-7-1.cpp 271715 2017-03-23 10:13:51Z piotr.tanski $
#include <cstdint>
#include <utility>
class A
{
public:
A() : x(0), y(0) {} // Compliant
A(std::int32_t first, std::int32_t second) : x(first), y(second) {} // Compliant
// -

// anyway, such
// a constructor
// cannot be
// defaulted.
A(const A& oth)
: x(oth.x),
y(oth.y) // Non-compliant - equivalent to the implicitly
// defined copy constructor
{
}
A(A&& oth)
: x(std::move(oth.x)),
y(std::move(
oth.y)) // Non-compliant - equivalent to the implicitly
// defined move constructor
{
}
~A() // Non-compliant - equivalent to the implicitly defined destructor
{
}

private:
std::int32_t x;
std::int32_t y;
};
class B
{
public:
B() {} // Non-compliant - x and y are not initialized
// should be replaced with: B() : x{0}, y{0} {}
B(std::int32_t first, std::int32_t second) : x(first), y(second) {} // Compliant
B(const B&) =
default; // Compliant - equivalent to the copy constructor of class A
B(B&&) =
default; // Compliant - equivalent to the move constructor of class A
~B() = default; // Compliant - equivalent to the destructor of class A

private:
std::int32_t x;
std::int32_t y;
};
class C
{
public:
C() = default;
// Compliant
C(const C&) = default; // Compliant
C(C&&) = default;
// Compliant
};
class D
{
public:
D() : ptr(nullptr) {}
// Compliant - this is not equivalent to what the
// implicitly defined default constructor would do
D(C* p) : ptr(p) {}

// Compliant

D(const D&) = default; // Shallow copy will be performed, user-defined copy

// constructor is needed to perform deep copy on ptr variable
D(D&&) = default; // ptr variable will be moved, so ptr will still point to
// the same object
~D() = default; // ptr will not be deleted, the user-defined destructor is
// needed to delete allocated memory

private:
C* ptr;

};
class E // Compliant - special member functions definitions are not needed as
// class E uses only implicit definitions
{
};

See also

HIC++ v4.0 [9]: 12.5.2 Define special members =default if the behavior is equivalent. C++ Core Guidelines [11]: C.80: Use =default if you have to be explicit about using the default semantics.

Rule A12-8-1 (required, implementation, automated)

Move and copy constructors shall move and respectively copy base classes and data members of a class, without any side effects.

Rationale

It is expected behavior that the move/copy constructors are only used to move/copy the object of the class type and possibly set moved-from object to a valid state. Move and copy constructors of an object are frequently called by STL algorithms and containers, so they are not supposed to provide any performance overhead or side effects that could affect moving or copying the object. Note: Class members that are not essential for a class invariant may not need to be copied (e.g. caches, debug information).

Example

// $Id: A12-8-1.cpp 303582 2018-01-11 13:42:56Z michal.szczepankiewicz $
#include <cstdint>
#include <utility>
class A
{
public:
    // Implementation
    A(A const& oth) : x(oth.x) // Compliant
    {
    }

private:
    std::int32_t x;
};
class B
{
public:
    // Implementation
    B(B&& oth) : ptr(std::move(oth.ptr)) // Compliant
    {
        oth.ptr = nullptr; // Compliant - this is not a side-effect, in this
                           // case it is essential to leave moved-from object
                           // in a valid state, otherwise double deletion will
                           // occur.
    }
    ~B() { delete ptr; }

private:
    std::int32_t* ptr;
};
class C
{
public:
    // Implementation
    C(C const& oth) : x(oth.x)
    {
        // ...
        x = x % 2; // Non-compliant - unrelated side-effect
    }

private:
    std::int32_t x;
};

class D
{
public:
    explicit D(std::uint32_t a) : a(a), noOfModifications(0) {}
    D(const D& d) : D(d.a) {} // compliant, not copying the debug information
                              // about number of modifications
    void SetA(std::uint32_t aa)
    {
        ++noOfModifications;
        a = aa;
    }
    std::uint32_t GetA() const noexcept
    {
        return a;
    }

private:
    std::uint32_t a;
    std::uint64_t noOfModifications;
};

See also

MISRA C++ 2008 [7]: Rule 12-8-1 A copy constructor shall only initialize its base classes and the nonstatic members of the class of which it is a member.

HIC++ v4.0 [9]: 12.5.3 Ensure that a user defined move/copy constructor only moves/copies base and member objects.

JSF December 2005 [8]: AV Rule 77: A copy constructor shall copy all data members and bases that affect the class invariant (a data element representing a cache, for example, would not need to be copied).

Rule A12-8-2 (advisory, implementation, automated)

User-defined copy and move assignment operators should use user-defined no-throw swap function.

Rationale

Using a non-throwing swap operation in the copy and move assignment operators helps to achieve Strong Exception Safety. Each assignment operator is also simplified because it does not require check for assignment to itself.

Example

// $Id: A12-8-2.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <cstdint>
#include <utility>
class A
{
public:
    A(const A& oth)
    {
        // ...
    }
    A(A&& oth) noexcept
    {
        // ...
    }
    A& operator=(const A& oth) & // Compliant
    {
        A tmp(oth);
        Swap(*this, tmp);
        return *this;
    }
    A& operator=(A&& oth) & noexcept // Compliant
    {
        A tmp(std::move(oth));
        Swap(*this, tmp);
        return *this;
    }
    static void Swap(A& lhs, A& rhs) noexcept
    {
        std::swap(lhs.ptr1, rhs.ptr1);
        std::swap(lhs.ptr2, rhs.ptr2);
    }

private:
    std::int32_t* ptr1;
    std::int32_t* ptr2;
};

class B
{
public:
    B& operator=(const B& oth) & // Non-compliant
    {
        if (this != &oth)
        {
            ptr1 = new std::int32_t(*oth.ptr1);
            ptr2 = new std::int32_t(
                      *oth.ptr2); // Exception thrown here results in
                                  // a memory leak of ptr1
        }

        return *this;

    }
    B& operator=(B&& oth) & noexcept // Non-compliant
    {
        if (this != &oth)
        {
            ptr1 = std::move(oth.ptr1);
            ptr2 = std::move(oth.ptr2);
            oth.ptr1 = nullptr;
            oth.ptr2 = nullptr;
        }

        return *this;
    }

private:
    std::int32_t* ptr1;
    std::int32_t* ptr2;
};

See also

HIC++ v4.0 [9]: 12.5.6 Use an atomic, non-throwing swap operation to implement the copy and move assignment operators

Rule A12-8-3 (required, implementation, partially automated)

Moved-from object shall not be read-accessed.

Rationale

Except in rare circumstances, an object will be left in an unspecified state after its values has been moved into another object. Accessing data members of such object may result in abnormal behavior and portability concerns.

Exception

It is permitted to access internals of a moved-from object if it is guaranteed to be left in a well-specified state. The following Standard Template Library functions are guaranteed to leave the moved-from object in a well-specified state: move construction, move assignment, “converting” move construction and “converting” move assignment of std::unique_ptr type move construction, move assignment, “converting” move construction, “converting” move assignment of std::shared_ptr type move construction and move assignment from a std::unique_ptr of std::shared_ptr type move construction, move assignment, “converting” move construction and “converting” move assignment of std::weak_ptr type std::move() of std::basic_ios type move constructor and move assignment of std::basic_filebuf type move constructor and move assignment of std::thread type move constructor and move assignment of std::unique_lock type move constructor and move assignment of std::shared_lock type move constructor and move assignment of std::promise type

move constructor and move assignment of std::future type move construction, move assignment, “converting” move construction and “converting” move assignment of std::shared_future type move constructor and move assignment of std::packaged_task type

Example

// $Id: A12-8-3.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <cstdint>
#include <iostream>
#include <memory>
#include <string>
void F1()
{
std::string s1{"string"};
std::string s2{std::move(s1)};
// ...
std::cout << s1 << "\n"; // Non-compliant - s1 does not contain "string"
// value after move operation
}
void F2()

{
std::unique_ptr<std::int32_t> ptr1 = std::make_unique<std::int32_t>(0);
std::unique_ptr<std::int32_t> ptr2{std::move(ptr1)};
std::cout << ptr1.get() << std::endl; // Compliant by exception - move
// construction of std::unique_ptr
// leaves moved-from object in a
// well-specified state

}

See also

SEI CERT C++ [10]: EXP63-CPP Do not rely on the value of a moved-from object.

Rule A12-8-4 (required, implementation, automated)

Move constructor shall not initialize its class members and base classes using copy semantics.

Rationale

Data members or base classes initialization in move constructor needs to be done with move semantics. Move construction is an optimization strategy and the copyinitialization for data members and base classes will have negative impact on the program’s performance, as well as it does not meet developer expectations.

Exception

In move constructor, copy initialization for data members of scalar types does not violate this rule. See: Scalar-Types.

Example

// $Id: A12-8-4.cpp 271696 2017-03-23 09:23:09Z piotr.tanski $
#include <cstdint>
#include <string>
class A
{
public:
// ...
A(A&& oth)
: x(std::move(oth.x)),
// Compliant
s(std::move(oth.s))
// Compliant
{
}

private:
std::int32_t x;
std::string s;

};

class B
{
public:
// ...
B(B&& oth)
: x(oth.x),

s(oth.s)

// Compliant by exception, std::int32_t is of scalar
// type
// Non-compliant

{
}

private:
std::int32_t x;
std::string s;

};
class C
{
public:
// ...
C(C&& oth)
: x(oth.x),
s(std::move(oth.s))
{
}

// Compliant
// Compliant

by exception

private:
std::int32_t x = 0;
std::string s = "Default string";

};

See also

SEI CERT C++ [10]: OOP11-CPP Do not copy-initialize members or base classes from a move constructor.

Rule A12-8-5 (required, implementation, automated)

A copy assignment and a move assignment operators shall handle self-assignment.

Rationale

User-defined copy assignment operator and move assignment operator need to prevent self-assignment, so the operation will not leave the object in an indeterminate state. If the given parameter is the same object as the local object, destroying objectlocal resources will invalidate them. It violates the copy/move assignment postconditions. Note that STL containers assume that self-assignment of an object is correctly handled. Otherwise it may lead to unexpected behavior of an STL container.

Self-assignment problem can also be solved using swap operators. See rule: A12-8-2.

Example

// $Id: A12-8-5.cpp 271773 2017-03-23 13:16:53Z piotr.tanski $
#include <cstdint>
#include <stdexcept>
struct A
{
std::int32_t number;

std::int32_t* ptr;

// Implementation

};
class B
{
public:
// ...
B& operator=(B const& oth) // Non-compliant
{
i = oth.i;
delete aPtr;

try
{

aPtr = new A(*oth.aPtr); // If this is the self-copy
// the oth.a_ptr is already

case, then
deleted

}
catch (std::bad_alloc&)
{
aPtr = nullptr;
}

return *this;

}

private:
std::int16_t i = 0;
A* aPtr = nullptr;

};
class C
{
public:
C& operator=(C const& oth) // Compliant
{
if (this != &oth)
{
A* tmpPtr = new A(*oth.aPtr);

i = oth.i;
delete aPtr;
aPtr = tmpPtr;

}

return *this;
}
C& operator=(C&& oth) // Compliant
{
if (this != &oth)
{

A* tmpPtr = new A{std::move(*oth.aPtr)};

i = oth.i;
delete aPtr;
aPtr = tmpPtr;

}

return *this;

}

private:
std::int16_t i = 0;

A* aPtr = nullptr;

};

See also

SEI CERT C++ [10]: OOP54-CPP Gracefully handle self-assignment. C++ Core Guidelines [11]: C.62: Make copy assignment safe for self-assignment.

Rule A12-8-6 (required, implementation, automated)

Copy and move constructors and copy assignment and move assignment operators shall be declared protected or defined “=delete” in base class.

Rationale

Invoking copy or move constructor or copy assignment or move assignment operator from the top of a class hierarchy bypasses the underlying implementations. This results in “slicing” where only the base sub-objects being copied or moved.

Example

// $Id: A12-8-6.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <memory>
#include <utility>
#include <vector>
class A // Abstract base class
{
public:
A() = default;
A(A const&) = default; // Non-compliant
A(A&&) = default;
// Non-compliant
virtual ~A() = 0;
A& operator=(A const&) = default; // Non-compliant

A& operator=(A&&) = default;
};
class B : public A
{
};
class C // Abstract base class
{
public:
C() = default;
virtual ~C() = 0;

// Non-compliant

protected:
C(C const&) = default;
// Compliant
C(C&&) = default;
// Compliant
C& operator=(C const&) = default; // Compliant
C& operator=(C&&) = default;
// Compliant
};
class D : public C
{
};
class E // Abstract base class
{
public:
E() = default;
virtual ~E() = 0;
E(E const&) = delete;
// Compliant
E(E&&) = delete;
// Compliant
E& operator=(E const&) = delete; // Compliant
E& operator=(E&&) = delete;
// Compliant
};
class F : public E
{
};
class G // Non-abstract base class
{
public:
G() = default;
virtual ~G() = default;
G(G const&) = default;
// Non-compliant
G(G&&) = default;
// Non-compliant
G& operator=(G const&) = default; // Non-compliant
G& operator=(G&&) = default;
// Non-compliant
};
class H : public G
{
};
void Fn1() noexcept
{
B obj1;
B obj2;
A* ptr1 = &obj1;

A* ptr2 = &obj2;
// Partial assignment only
*ptr1 = *ptr2;
*ptr1 = std::move(*ptr2); // Partial move only
D obj3;
D obj4;

C* ptr3 = &obj3;

C* ptr4 = &obj4;

//*ptr3 = *ptr4; // Compilation error - copy assignment operator of class C

// is protected

//*ptr3 = std::move(*ptr4); // Compilation error - move assignment operator

// of class C is protected
F obj5;
F obj6;

E* ptr5 = &obj5;

E* ptr6 = &obj6;

//*ptr5 = *ptr6; // Compilation error - use of deleted copy assignment

// operator

//*ptr5 = std::move(*ptr6); // Compilation error - use of deleted move

// assignment operator
H obj7;
H obj8;

G* ptr7 = &obj7;

G* ptr8 = &obj8;

// Partial assignment only
*ptr7 = *ptr8;
*ptr7 = std::move(*ptr8); // Partial move only
}
class I // Non-abstract base class
{
public:
I() = default;
~I() = default;

protected:
I(I const&) = default;
// Compliant
I(I&&) = default;
// Compliant
I& operator=(I const&) = default; // Compliant
I& operator=(I&&) = default;
// Compliant
};
class J : public I
{
public:
J() = default;
~J() = default;
J(J const&) = default;
J(J&&) = default;
J& operator=(J const&) = default;
J& operator=(J&&) = default;
};
void Fn2() noexcept
{
std::vector<I> v1;

// v1.push_back(J{}); // Compilation-error on calling a deleted move
// constructor of I class, slicing does not occur
// v1.push_back(I{}); // Compilation-error on calling a deleted move
// constructor of I class

std::vector<J> v2;
v2.push_back(J{}); // No compilation error

std::vector<std::unique_ptr<I>> v3;
v3.push_back(std::unique_ptr<I>{});
// No compilation error
v3.push_back(std::make_unique<I>()); // No compilation error
v3.push_back(std::make_unique<J>()); // No compilation error
v3.emplace_back();
// No compilation error

}

See also

MISRA C++ 2008 [7]: Rule 12-8-2 The copy assignment operator shall be declared protected or private in an abstract class. HIC++ v4.0 [9]: 12.5.8 Make the copy assignment operator of an abstract class protected or define it =delete. C++ Core Guidelines [11]: C.67: A base class should suppress copying, and provide a virtual clone instead if "‘copying"’ is desired. C++ Core Guidelines [11]: C.81: Use =delete when you want to disable default behavior (without wanting an alternative).

Rule A12-8-7 (advisory, implementation, automated)

Assignment operators should be declared with the ref-qualifier &.

Rationale

User declared assignment operators differ from built-in operators in a way that they accept rvalues as parameters, which is confusing. Adding & to the function declaration prohibits rvalue parameters and ensures that all of the calls can only be made on lvalue objects, which results with the same behavior as for built-in types. Note that this rule applies to all assignment operators, e.g. operator=(), operator*=(), operator+=.

Example

// $Id: A12-8-7.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <cstdint>
class A
{
public:
A() = default;
A& operator*=(std::int32_t i) // Non-compliant

{

// ...

return *this;

}

};
A F1() noexcept
{
return A{};
}
class B
{
public:
B() = default;

B& operator*=(std::int32_t) & // Compliant

{
// ...

return *this;

}

};
B F2() noexcept
{
return B{};
}
std::int32_t F3() noexcept
{
return 1;
}

int main(int, char**)

{
F1() *= 10; // Temporary result of f1() multiplied by 10. No compile-time

// error.

;

// f2() *= 10; // Compile-time error due to ref-qualifier

;
// f3() *= 10; // Compile-time error on built-in type

}

See also

HIC++ v4.0 [9]: 12.5.7 Declare assignment operators with the ref-qualifier &. cppreference.com [16]: Assignment operators.

Rule A13-1-2 (required, implementation, automated)

User defined suffixes of the user defined literal operators shall start with underscore followed by one or more letters.

Rationale

Suffixes that do not begin with the underscore character are reserved for operators provided by the standard library.

Example

// $Id: A13-1-2.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
constexpr long double operator"" _m(long double meters) // Compliant
{
// Implementation
return meters;
}
constexpr long double operator"" _kg(long double kilograms) // Compliant
{
// Implementation
return kilograms;
}
constexpr long double operator"" m(long double meters) // Non-compliant
{
// Implementation
return meters;
}
constexpr long double operator"" kilograms(
long double kilograms) // Non-compliant
{
// Implementation
return kilograms;
}
void Fn()
{
long double weight = 20.0_kg;
long double distance = 204.8_m;
}

See also

none

Rule A13-1-3 (required, implementation, automated)

User defined literals operators shall only perform conversion of passed parameters.

Rationale

It is expected behavior that the user-defined literals operators are only used to convert passed parameters to the type of declared return value. User-defined literals are not supposed to provide any other side-effects.

Example

// $Id: A13-1-3.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <cstdint>
#include <iostream>
struct Cube
{
unsigned long long int volume;
constexpr explicit Cube(unsigned long long int v) : volume(v) {}
};
constexpr Cube operator"" _m3(unsigned long long int volume)
{
return Cube(volume); // Compliant
}
struct Temperature
{
unsigned long long int kelvins;
constexpr explicit Temperature(unsigned long long int k) : kelvins(k) {}
};
constexpr Temperature operator"" _K(unsigned long long int kelvins)
{
return Temperature(kelvins); // Compliant
}
static void SumDistances(std::int32_t distance)
{
static std::int32_t overallDistance = 0;
overallDistance += distance;
}
struct Distance
{
long double kilometers;
explicit Distance(long double kms) : kilometers(kms) {}
};
Distance operator"" _m(long double meters)
{
SumDistances(meters); // Non-compliant - function has a side-effect
return Distance(meters / 1000);
}
void operator"" _print(const char* str)

{
std::cout << str << ’\n’; // Non-compliant - user-defined literal operator
// does not perform conversion and has a
// side-effect
}

See also

none

Rule A13-2-1 (required, implementation, automated)

An assignment operator shall return a reference to “this”.

Rationale

Returning a type “T&” from an assignment operator is consistent with the C++ Standard Library.

Example

// $Id: A13-2-1.cpp 271687 2017-03-23 08:57:35Z piotr.tanski $
class A
{
public:
// ...
A& operator=(const A&) & // Compliant
{
// ...
return *this;

}
};

class B
{
public:
// ...
const B& operator=(const B&) & // Non-compliant - violating consistency
// with standard types
{
// ...
return *this;

}
};

class C
{
public:
// ...
C operator=(const C&) & // Non-compliant
{
// ...
return *this;

}
};

class D
{
public:
// ...
D* operator=(const D&) & // Non-compliant

{
// ...
return this;
}
};

See also

HIC++ v4.0 [9]: 13.2.2 Ensure that the return type of an overloaded binary operator matches the built-in counterparts. C++ Core Guidelines [11]: F.47: Return T& from assignment operators.

Rule A13-2-2 (required, implementation, automated)

A binary arithmetic operator and a bitwise operator shall return a “prvalue”.

Rationale

Returning a type “T” from binary arithmetic and bitwise operators is consistent with the C++ Standard Library. See: prvalue.

Example

// $Id: A13-2-2.cpp 271687 2017-03-23 08:57:35Z piotr.tanski $
#include <cstdint>

class A
{
};

A operator+(A const&, A const&) noexcept // Compliant
{
return A{};
}
std::int32_t operator/(A const&, A const&) noexcept // Compliant
{
return 0;
}
A operator&(A const&, A const&)noexcept // Compliant
{
return A{};
}
const A operator-(A const&, std::int32_t) noexcept // Non-compliant
{

return A{};
}
A* operator|(A const&, A const&) noexcept // Non-compliant

{
return new A{};
}

See also

HIC++ v4.0 [9]: 13.2.2 Ensure that the return type of an overloaded binary operator matches the built-in counterparts.

Rule A13-2-3 (required, implementation, automated)

A relational operator shall return a boolean value.

Rationale

Returning a type “bool” from a relational operator is consistent with the C++ Standard Library.

Example

// $Id: A13-2-3.cpp 271687 2017-03-23 08:57:35Z piotr.tanski $
#include <cstdint>

class A
{
};

bool operator==(A const&, A const&) noexcept // Compliant
{
return true;
}
bool operator<(A const&, A const&) noexcept // Compliant
{
return false;
}
bool operator!=(A const& lhs, A const& rhs) noexcept // Compliant
{
return !(operator==(lhs, rhs));
}
std::int32_t operator>(A const&, A const&) noexcept // Non-compliant
{
return -1;
}
A operator>=(A const&, A const&) noexcept // Non-compliant
{
return A{};
}
const A& operator<=(A const& lhs, A const& rhs) noexcept // Non-compliant

{
return lhs;
}

See also

HIC++ v4.0 [9]: 13.2.2 Ensure that the return type of an overloaded binary operator matches the built-in counterparts.

Rule A13-3-1 (required, implementation, automated)

A function that contains “forwarding reference” as its argument shall not be overloaded.

Rationale

A template parameter that is declared “T&&” (Scott Meters called it a “universal reference”, while C++ Language Standard calls it a “forwarding reference”) will deduce for any type. Overloading functions with “forwarding reference” argument may lead to developer’s confusion on which function will be called.

Exception

Declaring an overloading function that takes a “forwarding reference” parameter to be “=delete” does not violate this rule. Declaring a “forwarding constructor” that is constrained (via SFINAE) to not match any other overloads also does not violate this rule, see A14-5-1.

Example

// $Id: A13-3-1.cpp 309903 2018-03-02 12:54:18Z christof.meerwald $
#include <cstdint>
template <typename T>
void F1(T&& t) noexcept(false)
{
}
void F1(
std::int32_t&& t) noexcept // Non-compliant - overloading a function with
// forwarding reference
{
}
template <typename T>
void F2(T&& t) noexcept(false)
{
}
void F2(std::int32_t&) = delete; // Compliant by exception

class A
{
public:
// Compliant by exception, constrained to not match copy/move ctors
template<typename T,
std::enable_if_t<! std::is_same<std::remove_cv_t<std::
remove_reference_t<T>>, A>::value> * = nullptr>

A(T &&value);

};

int main(int, char**)

{
std::int32_t x = 0;
F1(x);
// Calls f1(T&&) with T = int&
F1(+x); // Calls f1(std::int32_t&&)
F1(0); // Calls f1(std::int32_t&&)
F1(0U); // Calls f1(T&&) with T = unsigned int
F2(0); // Calls f2(T&&) with T = int
// f2(x); // Compilation error, the overloading function is deleted
}

See also

HIC++ v4.0 [9]: 13.1.2 If a member of a set of callable functions includes a universal reference parameter, ensure that one appears in the same position for all other members. Effective Modern C++ [13]: Item 26. Avoid overloading on universal references.

Rule A13-5-1 (required, implementation, automated)

If “operator[]” is to be overloaded with a non-const version, const version shall also be implemented.

Rationale

A non-const overload of the subscript operator allows an object to be modified, by returning a reference to member data, but it does not allow reading from const objects. The const version of “operator[]” needs to be implemented to ensure that the operator can be invoked on a const object. Note that one can provide a const version of operator[] (to support read-only access to elements), but without a non-const version.

Example

// $Id: A13-5-1.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <cstdint>

class Container1
{
public:
std::int32_t& operator[](
std::int32_t index) // Compliant - non-const version
{
return container[index];
}
std::int32_t operator[](
std::int32_t index) const // Compliant - const version
{
return container[index];
}

private:
static constexpr std::int32_t maxSize = 10;
std::int32_t container[maxSize];
};
void Fn() noexcept
{
Container1 c1;
std::int32_t e = c1[0]; // Non-const version called
c1[0] = 20;
// Non-const version called
Container1 const c2{};
e = c2[0]; // Const version called
// c2[0] = 20; // Compilation error
}
class Container2 // Non-compliant - only non-const version of operator[]
// implemented
{
public:
std::int32_t& operator[](std::int32_t index) { return container[index]; }

private:
static constexpr std::int32_t maxSize = 10;
std::int32_t container[maxSize];
};

See also

HIC++ v4.0 [9]: 13.2.4 When overloading the subscript operator (operator[]) implement both const and non-const versions.

Rule A13-5-2 (required, implementation, automated)

All user-defined conversion operators shall be defined explicit.

Rationale

Without explicit keyword, a single user defined conversion can be invoked in a standard conversion sequence, which can lead to accidental errors.

Example

// $Id: A13-5-2.cpp 303121 2018-01-09 09:03:52Z michal.szczepankiewicz $
class A
{
public:
explicit A(double d) : d(d) {}
explicit operator double() const { return d; } // Compliant
private:
double d;
};

int main(void)
{
A a{3.1415926535897932384626433832795028841971693993751058209749445923078};

double tmp1{a};
// float tmp2{a}; //compilation error instead of warning, prevents from data
// precision loss

return 0;
}

See also

HIC++ v4.0 [9]: 12.1.1: Do not declare implicit user defined conversions.

Rule A13-5-3 (advisory, implementation, automated)

User-defined conversion operators should not be used.

Rationale

Explicitly named conversions using dedicated member function eliminate any potential errors that can arise if the type conversion operators have to be used. If using conversion operators is fundamental in an application domain, see A13-5-2.

Example

// $Id: A13-5-3.cpp 305629 2018-01-29 13:29:25Z piotr.serwa $
#include <iostream>

class Complex
{
public:
Complex (double r, double i = 0.0) : re(r), im(i) {}
explicit operator double() const noexcept { return re; }
double AsDouble() const noexcept { return re; }
private:
double re;
double im;

};

int main(void)
{
Complex c(2.0f);

std::cout << (double) c << std::endl; //compliant with A13-5-2, non-compliant with A13-5-3

std::cout << c.AsDouble() << std::endl; //compliant

return 0;
}

See also

JSF December 2005 [8]: AV Rule 177: User-defined conversion functions should be avoided. C++ Core Guidelines [11]: C.164: Avoid conversion operators.

Rule A13-5-4 (required, implementation, automated)

If two opposite operators are defined, one shall be defined in terms of the other.

Rationale

Defining one operator in terms of the other simplifies maintenance and prevents from accidental errors during code development. Note: Completeness of relational operators can be achieved by implementing just operator== and operator< and using namespace rel_ops.

Example

// $Id: A13-5-4.cpp 328319 2018-08-03 14:08:42Z christof.meerwald $
#include <cstdint>

// non-compliant
class A
{
public:
explicit A(std::uint32_t d) : d(d) {}

friend bool operator==(A const & lhs, A const & rhs) noexcept
{
return lhs.d == rhs.d;
}
friend bool operator!=(A const & lhs, A const & rhs) noexcept
{
return lhs.d != rhs.d;
}

private:
std::uint32_t d;
};

// compliant
class B
{
public:
explicit B(std::uint32_t d) : d(d) {}

friend bool operator==(B const & lhs, B const & rhs) noexcept
{
return lhs.d == rhs.d;
}

friend bool operator!=(B const & lhs, B const & rhs) noexcept
{
return !(lhs == rhs);

}
private:
std::uint32_t d;
};

See also

JSF December 2005 [8]: AV Rule 85: When two operators are opposites (such as == and !=), both will be defined and one will be defined in terms of the other.

Rule A13-5-5 (required, implementation, automated)

Comparison operators shall be non-member functions with identical parameter types and noexcept.

Rationale

Any asymmetric behavior for comparison functions can be confusing. In order to achieve fully symmetric treatment, comparison functions need to be defined as nonmember functions, as the implicit object parameter of a member function does not allow user-defined conversions to be applied (but the right hand side would). Since comparison is a fundamental operation, it should never throw an exception. Note: This rule applies to ==, !=, <, <=, >, and >= Note: Declaring a comparison operator as a friend allows it to access internal data similar to a member function and is allowed by exception in rule A11-3-1.

Example

// $Id: A13-5-5.cpp 325916 2018-07-13 12:26:22Z christof.meerwald $
#include <cstdint>

class A
{
public:
explicit A(std::uint32_t d)
: m_d(d)
{}

bool operator ==(A const & rhs) const // Non-compliant: member, not noexcept
{
return m_d == rhs.m_d;
}

private:
std::uint32_t m_d;
};

class C
{
public:
operator A() const;
};

void Foo(A const & a, C const & c)
{
a == c; // asymmetric as "a ==c" compiles, but "c == a" doesn’t compile
}

class B
{
public:
explicit B(std::uint32_t d)
: m_d(d)
{}

Compliant: non-member, identical parameter types, noexcept friend bool operator
==(B const & lhs, B const & rhs) noexcept
{
return lhs.m_d == rhs.m_d;
}

private:
std::uint32_t m_d;
};

class D
{
public:
operator B() const;
};

void Bar(B const & b, D const & d)
{
b == d;
d == b;
}

See also

C++ Core Guidelines [11]: C.86: Make == symmetric with respect to operand types and noexcept

Rule A13-6-1 (required, implementation, automated)

Digit sequences separators ’ shall only be used as follows: (1) for decimal, every 3 digits, (2) for hexadecimal, every 2 digits, (3) for binary, every 4 digits.

Rationale

Since C++14 Language Standard it is allowed (optionally) to separate any two digits in digit sequences with separator ’. However, to meet developer expectations, usage of separator in integer and floating-point digit sequences should be unified: for decimal values, separator can be placed every 3 digits, e.g. 3’000’000, for hexadecimal values, separator can be placed every 2 digits, e.g. 0xFF’FF’FF’FF for binary values, separator can be placed very 4 digits, e.g. 0b1001’1101’0010

Example

// $Id: A13-6-1.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <cstdint>
void Fn() noexcept
{
std::uint32_t decimal1
= 3’000’000;
// Compliant
std::uint32_t decimal2
= 4’500;
// Compliant
std::uint32_t decimal3
= 54’00’30;
// Non-compliant
float decimal4 = 3.141’592’653;
// Compliant
float decimal5 = 3.1’4159’265’3;
// Non-compliant
std::uint32_t hex1 = 0xFF’FF’FF’FF;
// Compliant
std::uint32_t hex2 = 0xFAB’1’FFFFF;
// Non-compliant
std::uint8_t binary1 =
// Compliant
std::uint8_t binary2 = 0b10’00’10’01; // Non-compliant
}

See also

ISO 26262-6 [5]: 8.4.4 e) readability and comprehensibility

Rule A14-1-1 (advisory, implementation, non-automated)

A template should check if a specific template argument is suitable for this template.

Rationale

If a template class or function requires specific characteristics from a template type (e.g. if it is move constructible, copyable, etc.), then it needs to check whether the type matches the requirements to detect possible faults. The goal of this rule is to ensure that a template defines all of the preconditions that a template argument needs to fulfill without having any information about the specific class. This can be achieved in compile time using static_assert assertion.

Example

// $Id: A14-1-1.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <utility>
class A
{
public:
A() = default;
~A() = default;
A(A const&) = delete;
A& operator=(A const&) = delete;
A(A&&) = delete;
A& operator=(A&&) = delete;
};
class B
{
public:
B() = default;
B(B const&) = default;
B& operator=(B const&) = default;
B(B&&) = default;
B& operator=(B&&) = default;
};
template <typename T>

void F1(T const& obj) noexcept(false)
{
static_assert(
std::is_copy_constructible<T>(),
"Given template type is not copy constructible."); // Compliant
}
template <typename T>
class C
{
// Compliant
static_assert(std::is_trivially_copy_constructible<T>(),
"Given template type is not trivially copy constructible.");

// Compliant
static_assert(std::is_trivially_move_constructible<T>(),
"Given template type is not trivially move constructible.");

// Compliant
static_assert(std::is_trivially_copy_assignable<T>(),
"Given template type is not trivially copy assignable.");

// Compliant
static_assert(std::is_trivially_move_assignable<T>(),
"Given template type is not trivially move assignable.");

public:
C() = default;
C(C const&) = default;
C& operator=(C const&) = default;
C(C&&) = default;
C& operator=(C&&) = default;

private:
T c;
};
template <typename T>
class D
{
public:
D() = default;
D(D const&) = default;
// Non-compliant - T may not be copyable
D& operator=(D const&) = default; // Non-compliant - T may not be copyable
D(D&&) = default;
// Non-compliant - T may not be movable
D& operator=(D&&) = default;// Non-compliant - T may not be movable

private:
T d;
};
void F2() noexcept
{
A a;

B b;
// f1<A>(a); // Class A is not copy constructible, compile-time error
// occurs
F1<B>(b); // Class B is copy constructible
// C<A> c1; // Class A can not be used for template class C, compile-time
// error occurs
C<B> c2; // Class B can be used for template class C
D<A> d1;
// D<A> d2 = d1; // Class D can not be copied, because class A is not
// copyable, compile=time error occurs
// D<A> d3 = std::move(d1); // Class D can not be moved, because class A is
// not movable, compile-time error occurs
D<B> d4;
D<B> d5 = d4;
D<B> d6 = std::move(d4);
}

See also

JSF December 2005 [8]: AV Rule 103: Constraint checks should be applied to template arguments. C++ Core Guidelines [11]: T.150: Check that a class matches a concept using static_assert.

Rule A14-5-1 (required, implementation, automated)

A template constructor shall not participate in overload resolution for a single argument of the enclosing class type.

Rationale

A template constructor is never a copy or move constructor and therefore doesn’t prevent the implicit definition of a copy or move constructor even if the template constructor looks similar and might easily be confused. At the same time, copy or move operations do not necessarily only use a copy or move constructor, but go through the normal overload resolution process to find the best matching function to use. This can cause confusion in the following cases: a template constructor that looks like a copy/move constructor is not selected for a copy/move operation because the compiler has generated an implicit copy/move constructor as well a template constructor is selected in preference over a copy/move constructor because the template constructor is a better match

To avoid these confusing situations, template constructors shall not participate in overload resolution for a single argument of the enclosing class type to avoid a template constructor being selected for a copy/move operation. It also makes it clear that the constructor is not a copy/move constructor and that it does not prevent the implicit generation of copy/move constructors.

Example

// $Id: A14-5-1.cpp 309903 2018-03-02 12:54:18Z christof.meerwald $
#include <cstdint>
#include <type_traits>

class A
{
public:
// Compliant: template constructor does not participate in overload
//
resolution for copy/move operations
template<typename T,

std::enable_if_t<! std::is_same<std::remove_cv_t<T>, A>::value> * = nullptr>

A(const T &value)
: m_value { value }
{}

private:
std::int32_t m_value;
};

void Foo(A const &a)
{
A myA { a }; // will use the implicit copy ctor, not the template converting
ctor

A a2 { 2 }; // will use the template converting ctor
}

class B
{
public:
B(const B &) = default;
B(B &&) = default;

// Compliant: forwarding constructor does not participate in overload
//
resolution for copy/move operations
template<typename T,
std::enable_if_t<! std::is_same<std::remove_cv_t<std::
remove_reference_t<T>>, B>::value> * = nullptr>

B(T &&value);

};

void Bar(B b)
{

B myB { b }; // will use the copy ctor, not the forwarding ctor
}

class C
{
public:
C(const C &) = default;
C(C &&) = default;

// Non-Compliant: unconstrained template constructor
template<typename T>
C(T &);
};

void Bar(C c)
{
C myC { c }; // will use template ctor instead of copy ctor
}

See also

MISRA C++ 2008 [7]: M14-5-2: A copy constructor shall be declared when there is a template constructor with a single parameter that is a generic parameter.

Rule A14-5-2 (advisory, design, partially-automated)

Class members that are not dependent on template class parameters should be defined in a separate base class.

Rationale

Having non-dependent members in a class template can lead to unnecessary template instantiations and potential code bloat. It is therefore preferred to move those members to a non-dependent base class so they can be used without any template instantiation.

Example

// $Id: A14-5-2.cpp 323444 2018-06-22 14:38:18Z christof.meerwald $
#include <cstdint>

template<typename T>
class A
{
public:
enum State // Non-Compliant: member doesn’t depend on template parameter
{
State1,
State2
};

State GetState();

};

class B_Base
{
public:
enum State // Compliant: not a member of a class template
{
State1,
State2
};
};

template<typename T>
class B : B_Base
{
public:
State GetState();
};

See also

C++ Core Guidelines [11]: T.62: Place non-dependent class template members in a non-templated base class

Rule A14-5-3 (advisory, design, automated)

A non-member generic operator shall only be declared in a namespace that does not contain class (struct) type, enum type or union type declarations.

Rationale

Argument-dependent lookup (ADL) adds additional associated namespaces to the set of scopes searched when lookup is performed for the names of called functions. A generic operator found in one of these additional namespaces would be added to the overload set and choosen by overload resolution. ADL is complicated by several possible use forms for operators (via function calls and via expression, operators can be declared as members and as non-members) and lookup in those cases is different, which is likely to be inconsistent with developer expectation. Generic operator is a non-member operator template that can be called without explicit template arguments and has at least one generic parameter. A template type parameter T is a generic parameter if, in the function declaration, it has the (possibly cv-qualified) form of T, or T & or T &&.

Example

// $Id: A14-5-3.cpp $
#include <cstdint>

template<typename T>

class B
{
public:
bool operator+( long rhs );

void f()
{

*this + 10;
}
};

namespace NS1
{
class A {};

template<typename T>
bool operator+( T, std::int32_t ); // Non-Compliant: a member of namespace
// with other declarations
}

namespace NS2
{
void g();

template<typename T>
bool operator+( T, std::int32_t ); // Compliant: a member of namespace
// with declarations of functions only
}

template class B<NS1::A>; // NS1::operator+ will be used in function B::f()
// instead of B::operator+

See also

MISRA C++ 2008 [7]: M14-5-1: A non-member generic function shall only be declared in a namespace that containes only operator declarations.

Rule M14-5-3 (required, implementation, automated)

A copy assignment operator shall be declared when there is a template assignment operator with a parameter that is a generic parameter. See MISRA C++ 2008 [7]

Rule M14-6-1 (required, implementation, automated)

In a class template with a dependent base, any name that may be found in that dependent base shall be referred to using a qualified-id or this->. See MISRA C++ 2008 [7]

Rule A14-7-1 (required, implementation, automated)

A type used as a template argument shall provide all members that are used by the template.

Rationale

If a type used as a template argument does not provide all the members used by the template, the instantiation of the template will result in an ill-formed program. It is not clear for developer whether the template should be used with the type.

Example

// $Id: A14-7-1.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <cstdint>
class A
{
public:
void SetProperty(std::int32_t x) noexcept { property = x; }
void DoSomething() noexcept {}

private:
std::int32_t property;
};
struct B
{
};
class C
{
public:
void DoSomething() noexcept {}
};
template <typename T>
class D
{
public:
void F1() {}
void F2()
{
T t;

t.SetProperty(0);
}
void F3()
{
T t;
t.DoSomething();
}
};

void Fn() noexcept
{
D<A> d1; // Compliant - struct A provides all needed members
d1.F1();
d1.F2();
d1.F3();

D<B> d2; // Non-compliant - struct B does not provide needed members
d2.F1();
// d2.f2(); // Compilation error - no ’property’ in struct B
// d2.f3(); // Compilation error - no member named ’doSomething’ in struct
// B

D<C> d3; // Non-compliant - struct C does not provide property
d3.F1();
// d3.F2(); // Compilation error - no property in struct C
d3.F3();
}

See also

MISRA C++ 2008 [7]: Rule 14-7-2 (Required) For any given template specialization, an explicit instantiation of the template with the template arguments used in the specialization shall not render the program ill-formed.

Rule A14-7-2 (required, implementation, automated)

Template specialization shall be declared in the same file (1) as the primary template (2) as a user-defined type, for which the specialization is declared.

Rationale

It is undefined behavior, when a compiler sees the (partial or explicit) template specialization after it already has instantiated the primary or less specialized template. Moreover, the case (2) allows compile-time interfaces to be extensible, as developers can safely provide custom specializations e.g. for traits classes or std::hash.

Example

// $Id: A14-7-2.cpp 312645 2018-03-21 11:44:35Z michal.szczepankiewicz $
#include <cstdint>

//in A.hpp

#include <functional>

struct A
{
std::uint8_t x;
};

namespace std {

//compliant, case (2)
//template specialization for the user-defined type
//in the same file as the type declaration
template <>
struct hash<A>
{
size_t operator()(const A& a) const noexcept
{
return std::hash<decltype(a.x)>()(a.x);
}
};

}

//traits.hpp

#include <type_traits>
#include <cstdint>

template <typename T>
struct is_serializable : std::false_type {};

//compliant, case (1)
template <>
struct is_serializable<std::uint8_t> : std::true_type {};

//func.cpp

#include <vector>

//non-compliant, not declared
//in the same file as
//is_serializable class
template <>
struct is_serializable<std::uint16_t> : std::true_type {};

template <typename T, typename = std::enable_if<is_serializable<T>::value>>
std::vector<std::uint8_t> serialize(const T& t)
{
//only a basic stub

return std::vector<std::uint8_t>{t};
}

#include <string>
int main()
{
serialize(std::uint8_t{3});
}

See also

MISRA C++ 2008 [7]: Rule 14-7-2 (Required) For any given template specialization, an explicit instantiation of the template with the template arguments used in the specialization shall not render the program ill-formed.

Rule A14-8-2 (required, implementation, automated)

Explicit specializations of function templates shall not be used.

Rationale

Specializations of function templates do not participate in overload resolution. They are only considered after their primary template has been selected during overload resolution. This is highly dependent on the declaration order of overloads and specializations and may be inconsistent with developer expectations. A non-template function is always selected over a function template specialization if they are otherwise an equally good match, which also may be confusing for developers.

Function templates cannot be partially specialized, which may lead to troublesome implementations. If a partial specialization is required, then it is recommended to write a single function template that delegates to a class template (which can be partially specialized).

Example

// $Id: A14-8-2.cpp 312698 2018-03-21 13:17:36Z michal.szczepankiewicz $
#include <cstdint>
#include <memory>
#include <iostream>

template <typename T>
void F1(T t)
{
//compliant, (a)
std::cout << "(a)" << std::endl;
}

template <>
void F1<>(uint16_t* p)

{
//non-compliant
//(x), explicit specialization of
//(a), not (b), due to declaration
//order
std::cout << "(x)" << std::endl;
}

template <typename T>
void F1(T* p)

{
//compliant, (b), overloads (a)
std::cout << "(b)" << std::endl;
}

template <>
void F1<>(uint8_t* p)

{
//non-compliant
//(c), explicit specialization of (b)
std::cout << "(c)" << std::endl;
}

void F1(uint8_t* p)

{
//compliant
//(d), plain function, overloads with (a), (b)
//but not with (c)
std::cout << "(d)" << std::endl;
}

int main(void)
{
auto sp8 = std::make_unique<uint8_t>(3);
auto sp16 = std::make_unique<uint16_t>(3);

F1(sp8.get()); //calls (d), which might be
//confusing, but (c) is non-compliant

F1(sp16.get()); //calls (b), which might be
//confusing, but (b) is non-compliant

}

See also

MISRA C++ 2008 [7]: 14-8-1: Overloaded function templates shall not be explicitly specialized.

MISRA C++ 2008 [7]: 14-8-2: The viable function set for a function call should either contain no function specializations, or only contain function specializations.

HIC++ v4.0 [9]: 14.2.2: Do not explicitly specialize a function template that is overloaded with other templates. C++ Core Guidelines [11]: T.144: Don’t specialize function templates.

Advantages of using exceptions “The exception handling mechanism can provide an effective and clear means of handling error conditions, particularly where a function needs to return both some desired result together with an indication of success or failure. However, because of its ability to transfer control back up the call tree, it can also lead to code that is difficult to understand. Hence it is required that the mechanism is only used to capture behavior that is in some sense undesirable, and which is not expected to be seen in normal program execution.” [MISRA C++ 2008] “The preferred mechanism for reporting errors in a C++ program is exceptions rather than using error codes. A number of core language facilities, including dynamic_cast, operator new(), and typeid, report failures by throwing exceptions. In addition, the C++ standard library makes heavy use of exceptions to report several different kinds of failures. Few C++ programs manage to avoid using some of these facilities.” [ISO C++ Core Guidelines]. Consequently, C++ programs need to be prepared for exceptions to occur and need to handle each appropriately. Challenges of using exceptions Issue:

Solution:

Correctness of the exception handling

Exception handling mechanism is implemented by the compiler (by its library functions and machine code generator) and defined by the C++ Language Standard. Rule A1-2-1 requires that the compiler (including its exception handling routines), when used for safety-related software, meets appropriate safety requirements.

Hidden control flow

ISO 26262-6 (Table *) recommends “no hidden data flow or control flow” for ASIL A software and highly recommends it for ASIL B/C/D. Therefore, the Rule A15-0-1 prohibits the usage of exceptions for normal control flow of software - they are allowed only for errors where a function failed to perform its assigned task.

Guidelines for the use of the C++14 language in critical and safety-related systems

Additional exit point from functions

ISO 26262-6 (Table *) highly recommends “one entry and one exit point in subprograms and functions” for ASIL A software. Therefore, the Rule A15-0-1 prohibits the usage of exceptions for normal control flow of software - they are allowed only for errors where a function failed to perform its assigned task.

Code readability

If exceptions are used correctly, in particularly by using checked and unchecked exception types, see Rules: A15-0-4 and A15-0-5, the code is easier to read and maintain than if using error codes. It avoids nesting if/else error-checking statements.

Exception

safety and program state consistency after exception is thrown

The Rule A15-0-2 requires that functions provide at least “basic exception safety” (Note: this C++ term is not related to functional safety)

Impact on runtime performance

If a function does not throw an exception (i.e. error conditions do not occur), then there could be a little overhead due to exception handling mechanism initialization. However, some compilers offer “zero cost exception handling”, which means that there is no performance overhead if the exception is not thrown.

Impact on worst-case execution time

The A15-0-7 rule requires that the exception handling mechanism provides real-time implementation. Note that this is not the case for e.g. GCC compiler that allocates dynamic memory on throwing an exception. However, it is possible to fix it simply by avoiding memory allocation.

Maturity of exceptions

Exceptions are a widespread concept in several programming languages, not only in C++, but also in e.g. Ada, Java, Modula-3, ML, OCaml, Python, Ruby, C#, Lisp, Eiffel, and Modula-2.

Tool support

There are several tools that support exceptions well: compilers (e.g. gcc, clang, visual studio), IDEs (e.g. eclipse, clion, visual studio), static analysis tools (e.g. QA C++, Coverity Prevent) and compiler validation suites (e.g. SuperTest).

Appropriate usage of exceptions in implementation

Exceptions need to be used properly in the code, therefore this document specifies almost 40 precise rules defining how to code using exceptions, in particular defining the rules for checked/unchecked exceptions.

Table 6.1: Challenges of exceptions usage

Checked and unchecked exceptions

Like MISRA introduces a concept of "underlying type", AUTOSAR C++14 Guidelines introduces a concept of unchecked and checked exceptions. This is based on the classification used in Java language, having as a goal an efficient, complete and consistent way of specifying the exceptions. There are therefore two exclusive categories of exceptions: Checked Exceptions: Used to represent errors that are expected and reasonable to recover from, so they are supposed to be documented by functions using a dedicated tag (e.g. @throws) and have to be either handled or documented (in the same way) by caller functions. Exceptions are marked as Checked using a separate tag (e.g. @checkedException) that precedes an exception class declaration. Unchecked Exceptions: Used to represent errors that a program typically can not recover from. However, unchecked exceptions can be documented by functions, i.e in cases when all preconditions of thrown exception are defined and known. It is context dependent where such an exception can be caught (e.g. is it done before main function) and what is the proper handling (e.g. other than program termination). However, it is not forced so that unchecked exceptions are documented by caller functions (even if they are documented by called functions). By default, all exceptions are unchecked (also from third-party libraries used), unless their definition is preceded by the dedicated tag. “Checked exceptions are a wonderful feature of the Java programming language. Unlike return codes, they force the programmer to deal with exceptional conditions, greatly enhancing reliability.” [Effective Java 2nd Edition [15]] The following sections specify several specific rules defining the usage of exceptions, in particular concerning the use of unchecked and checked exceptions.

Rule A15-0-1 (required, architecture / design /implementation, non-automated)

A function shall not exit with an exception if it is able to complete its task.

Rationale

“The notion of an exception is provided to help get information from the point where an error is detected to a point where it can be handled. A function that cannot cope with a problem throws an exception, hoping that its (direct or indirect) caller can handle the problem. A function that wants to handle a kind of problem indicates that by catching the corresponding exception.” [The C++ Programming Language [14]] Exceptions are only supposed to be used to capture incorrect, and which is not expected to be seen in normal program, execution. Using exception handling mechanism to transfer control back up the call stack, in error-free situation, leads to

code that is difficult to understand and significantly less efficient than returning from a function. Note that most of the monitoring or supervision functions are not supposed to throw an exception when an error is detected.

Example

//% $Id: A15-0-1.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <fstream>
#include <stdexcept>
#include <string>
#include <vector>
std::uint8_t ComputeCrc(std::string& msg);
bool IsMessageCrcCorrect1(std::string& message)
{
std::uint8_t computedCRC = ComputeCrc(message);
std::uint8_t receivedCRC = message.at(0);

if (computedCRC != receivedCRC)
{
throw std::logic_error(
"Computed CRC is invalid."); // Non-compliant - CheckMessageCRC()
// was able to perform
// its task, nothing exceptional about its invalid result
}

return true;
}
bool IsMessageCrcCorrect2(std::string& message)
{
bool isCorrect = true;
std::uint8_t computedCRC = ComputeCrc(message);
std::uint8_t receivedCRC = message.at(0);

if (computedCRC != receivedCRC)
{
isCorrect =
false;
// Compliant - if CRC is not correct, then return "false"
}

return isCorrect;
}
void SendData(std::string message)
{
if (message.empty())
{
throw std::logic_error("Preconditions are not met."); // Compliant // SendData() was
// not able to
// perform its
// task

}

bool sendTimeoutReached = false;

// Implementation
if (sendTimeoutReached)
{
throw std::runtime_error(
"Timeout on sending a message has been reached."); // Compliant // SendData()
// did not
//
perform its
//
task

}
}
std::int32_t FindIndex(std::vector<std::int32_t>& v, std::int32_t x) noexcept
{
try
{
std::size_t size = v.size();
for (std::size_t i = 0U; i < size; ++i)
{
if (v.at(i) == x) // v.at() throws an std::out_of_range exception
{
throw i; // Non-compliant - nothing exceptional about finding a
// value in vector
}
}
}

catch (std::size_t
foundIdx) // Non-compliant // value in vector

nothing exceptional about finding a

{
return foundIdx;
}

catch (std::out_of_range&
e)
{
return -1;
}

// Compliant - std::out_of_range error shall be handled

return -1;
}
bool ReadFile(std::string& filename) noexcept
{
try
{
std::ifstream file(filename, std::ios_base::in);

if (!file.is_open())
{
throw std::runtime_error(
"File cannot be opened"); // Compliant - error on opening a
// file is an exceptional case

}

char c = file.get();

if (!file.good())
{
throw std::runtime_error(
"Cannot read from file"); // Compliant - error on reading from
// file is an exceptional case

}
}

catch (std::exception& e)
{
return false;
}

return true;
}
void Fn1(
std::uint32_t x) // Non-compliant - inefficient and less readable version
// than its obvious alternative, e.g. fn2()
// function
{
try
{
if (x < 10)
{
throw 10;
}

// Action "A"
}

catch (std::int32_t y)
{
// Action "B"
}
}
void Fn2(
std::uint32_t x) // Compliant - the same functionality as fn1() function
{
if (x < 10)
{
// Action "B"
}

else
{
// Action "A"
}
}

See also

MISRA C++ 2008 [7]: 15-0-1 (Document) Exceptions shall only be used for error handling. C++ Core Guidelines [11]: E.3: Use exceptions for error handling only Effective Java 2nd Edition [15]: Item 57: Use exceptions only for exceptional conditions The C++ Programming Language [14], 13.1.1. Exceptions

Rule A15-0-2 (required, architecture / design / implementation,partially automated)

At least the basic guarantee for exception safety shall be provided for all operations. In addition, each function may offer either the strong guarantee or the nothrow guarantee

Rationale

Exceptions introduce additional data flow into a program. It is important to consider all the effects of code taking such paths to always recover from an exception error properly and always preserve object’s invariants. “Well-designed functions are exception safe, meaning they offer at least the basic exception safety guarantee (i.e., the basic guarantee). Such functions assure callers that even if an exception is thrown, program invariants remain intact (i.e., no data structures are corrupted) and no resources are leaked. Functions offering the strong exception safety guarantee (i.e., the strong guarantee) assure callers that if an exception arises, the state of the program remains as it was prior to the call.” [effective modern c++] The C++ standard library always provides one of the following guarantees for its operations, the same needs to be followed by code compliant to the guidelines. “ Basic guarantee for all operations: The basic invariants of all objects are maintained, and no resources, such as memory, are leaked. In particular, the basic invariants of every built-in and standard-library type guarantee that you can destroy an object or assign to it after every standard-library operation Strong guarantee for key operations: in addition to providing the basic guarantee, either the operation succeeds, or it has no effect. Nothrow guarantee for some operations: in addition to providing the basic guarantee, some operations are guaranteed not to throw any exception.

” [C++ Programming Reference] Nothrow means in this context that the function not only does not exit with an exception, but also that internally an exception cannot occur.

Example

//% $Id: A15-0-2.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <cstdint>
#include <cstring>
class C1
{
public:
C1(const C1& rhs)
{
CopyBad(rhs);
// Non-compliant if an exception is thrown, an object
// will be left in
an indeterminate state
CopyGood(rhs); // Compliant - full object will be properly copied or
// none of its properties will be changed
}
~C1() { delete[] e; }
void CopyBad(const C1& rhs)
{
if (this != &rhs)
{
delete[] e;
e = nullptr;
// e changed before the block where an exception can
// be thrown
s = rhs.s;
// s changed before the block where an exception can be
// thrown

if (s > 0)
{
e = new std::int32_t[s]; // If an exception will be thrown
// here, the
// object will be left in an indeterminate
// state

}

std::memcpy(e, rhs.e, s * sizeof(std::int32_t));

}
}
void CopyGood(const C1& rhs)
{
std::int32_t* eTmp = nullptr;

if (rhs.s > 0)
{
eTmp = new std::int32_t[rhs.s]; // If an

exception will be thrown
// here, the
// object will be left unchanged

std::memcpy(eTmp, rhs.e, rhs.s * sizeof(std::int32_t));

}

delete[] e;
e = eTmp;
s = rhs.s;
}

private:
std::int32_t* e;

std::size_t s;
};
class A
{
public:
A() = default;
};
class C2
{
public:
C2() : a1(new A), a2(new A) // Non-compliant - if a2 memory allocation
// fails, a1 will never be deallocated
{
}

private:
A* a1;
A* a2;

};
class C3
{
public:
C3() : a1(nullptr), a2(nullptr) // Compliant
{
try
{
a1 = new A;
a2 = new A;
// If memory allocation for a2 fails, catch-block will
// deallocate a1
}

catch (...)
{
delete a1;
a1 = nullptr;
delete a2;
a2 = nullptr;
throw;

}
}

private:
A* a1;

A* a2;
};

See also

SEI CERT C++ [10]: ERR56-CPP. Guarantee exception safety

Rule A15-0-3 (required, implementation, non-automated)

Exception safety guarantee of a called function shall be considered.

Rationale

Supplying an external function with an object that throws an exception on specific operations (e.g. in special member functions) may lead to function’s unexpected behavior. Note that the result of a function call supplied with an object which throws on specific operations may differ when the function guarantees the basic exception safety and the strong exception safety.

Example

//% $Id: A15-0-3.cpp 271687 2017-03-23 08:57:35Z piotr.tanski $
#include <cstdint>
#include <stdexcept>
#include <vector>
class A
{
public:
explicit A(std::int32_t value) noexcept(false) : x(value)
{
if (x == 0)
{
throw std::invalid_argument("Constructor: Invalid Argument");
}
}

private:
std::int32_t x;
};
int main(int, char**)

{
constexpr std::int32_t limit = 10;
std::vector<A> vec1; // Constructor and assignment operator of A class
// throw exceptions

try
{
for (std::int32_t i = 1; i < limit; ++i)
{

vec1.push_back(A(i)); // Constructor of A class will not throw for
// value from 1 to 10

}

vec1.emplace(vec1.begin(),
0); // Non-compliant - constructor A(0) throws
in an
// emplace() method
of std::vector. This leads to
// unexpected result of emplace()
method. Throwing an
// exception inside
an object constructor in emplace()
//
leads to duplication of one of vector’s
elements.
// Vector invariants are valid and the object is destructible.
}
catch (std::invalid_argument& e)
{
// Handle an exception
}

std::vector<A> vec2;
vec2.reserve(limit);
try
{
for (std::int32_t i = limit - 1; i >= 0; --i)
{
vec2.push_back(A(i)); // Compliant - constructor of A(0) throws for
// i = 0, but in this case strong exception
// safety is guaranteed. While push_back()
// offers strong exception safety guarantee,
// push_back can only succeed to add a new
// element or fails and does not change the
// container
}
}
catch (std::invalid_argument& e)
{
// Handle an exception
}

return 0;
}

See also

none

Rule A15-0-4 (required, architecture / design /implementation, non-automated)

Unchecked exceptions shall be used to represent errors from which the caller cannot reasonably be expected to recover.

Rationale

Problems that are unpreventable and not expected by the caller are represented with instances of unchecked exceptions category. Such problems include: Software errors, i.e. preconditions/postconditions violations, arithmetic errors, failed assertions, sanity checks or invalid variable access, that in C++ are typically represented by logic_error, bad_exception, bad_cast and bad_typeid exceptions or their subclasses Internal errors of the executable (like VirtualMachineError of Java language), that in C++ are represented by bad_alloc and bad_array_new_length exceptions

It is not possible to recover from such errors in a meaningful way.

Example

//% $Id: A15-0-4.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <cstdint>
#include <stdexcept>
#include <vector>
class InvalidArguments : public std::logic_error // Compliant - invalid
// arguments error is
// "unchecked" exception
{
public:
using std::logic_error::logic_error;
};
class OutOfMemory : public std::bad_alloc
Compliant - insufficient memory
error is "unchecked" exception
{
public:
using std::bad_alloc::bad_alloc;
};
class DivisionByZero : public std::logic_error
Compliant - division by zero
error is "unchecked"
exception
{
public:
using std::logic_error::logic_error;
};
class CommunicationError : public std::logic_error // Non-compliant // communication error
// should be "checked"
// exception but defined to be "unchecked"
{
public:
using std::logic_error::logic_error;
};
double Division(std::int32_t a, std::int32_t b) noexcept(false)
{
// ...
if (b == 0)

{
throw DivisionByZero(
"Division by zero error");
}

// Unchecked exception thrown correctly

// ...
}
void Allocate(std::uint32_t bytes) noexcept(false)
{
// ...
throw OutOfMemory(); // Unchecked exception thrown correctly
}
void InitializeSocket() noexcept(false)
{
bool validParameters = true;

// ...
if (!validParameters)
{
throw InvalidArguments("Invalid parameters passed"); // Unchecked
// exception
// thrown
// correctly

}
}
void SendData(std::int32_t socket) noexcept(false)
{
// ...
bool isSentSuccessfully = true;

// ...
if (!isSentSuccessfully)
{
throw CommunicationError("Could not send data"); // Unchecked exception
// thrown when checked
// exception should
// be.

}
}
void IterateOverContainer(const std::vector<std::int32_t>& container,
std::uint64_t length) noexcept(false)
{
for (std::uint64_t idx{0U}; idx < length; ++idx)
{
int32_t value = container.at(idx); // at() throws std::out_of_range
// exception
when passed integer
// exceeds the size of
container.
// Unchecked exception
thrown
// correctly
}
}

See also

Effective Java: Item 58: Use checked exceptions for recoverable conditions and runtime exceptions for programming errors, Item 60: Favor the use of standard exceptions

Rule A15-0-5 (required, architecture / design /implementation, non-automated)

Checked exceptions shall be used to represent errors from which the caller can reasonably be expected to recover.

Rationale

All expected by the caller, but also reasonable to recover from, problems are represented with instances of checked exceptions. Such problems include input/output and other application’s runtime errors. It is possible to handle such errors in a meaningful way. “Overuse of checked exceptions can make an API far less pleasant to use. If a method throws one or more checked exceptions, the code that invokes the method must handle the exceptions in one or more catch blocks, or it must declare that it throws the exceptions and let them propagate outward. Either way, it places a nontrivial burden on the programmer. The burden is justified if the exceptional condition cannot be prevented by proper use of the API and the programmer using the API can take some useful action once confronted with the exception. Unless both of these conditions hold, an unchecked exception is more appropriate.” [Effective Java 2nd Edition [15]]

Example

//% $Id: A15-0-5.cpp 309502 2018-02-28 09:17:39Z michal.szczepankiewicz $
#include <cstdint>
#include <stdexcept>
#include <system_error>

// @checkedException
class CommunicationError
: public std::exception // Compliant - communication error is "checked"
{
public:
explicit CommunicationError(const char* message) : msg(message) {}

CommunicationError(CommunicationError const&) noexcept = default;
CommunicationError& operator=(CommunicationError const&) noexcept = default;
~CommunicationError() override = default;

const char* what() const noexcept override { return msg; }

private:
const char* msg;

};

// @checkedException
class BusError
: public CommunicationError // Compliant - bus error is "checked"
{
public:
using CommunicationError::CommunicationError;
};

// @checkedException
class Timeout : public std::runtime_error // Compliant - communication timeout
// is "checked"
{
public:
using std::runtime_error::runtime_error;
};

// @checkedException
class PreconditionsError : public std::exception // Non-compliant - error on
// preconditions
check should
// be "unchecked" but is
// defined to be
"checked"
{
// Implementation
};

void Fn1(std::uint8_t* buffer, std::uint8_t bufferLength) noexcept(false)

{
bool sentSuccessfully = true;

// ...
if (!sentSuccessfully)
{
throw CommunicationError(
"Could not send data");
}
}

// Checked exception thrown correctly

void Fn2(std::uint8_t* buffer, std::uint8_t bufferLength) noexcept(false)

{
bool initSuccessfully = true;

if (!initSuccessfully)
{
throw PreconditionsError(); // An exception thrown on preconditions
// check failure should be "Unchecked", but
// PreconditionsError is "Checked"
}

// ...
bool sentSuccessfully = true;

bool isTimeout = false;

// ...
if (!sentSuccessfully)
{
throw BusError(
"Could not send data");
}

// Checked exception thrown correctly

// ...
if (isTimeout)
{
throw Timeout("Timeout reached"); // Checked exception thrown correctly
}
}
void Fn3(std::uint8_t* buffer) noexcept(false)

{
bool isResourceBusy = false;

// ...
if (isResourceBusy)
{
throw std::runtime_error(
"Resource is busy now");
}
}
class Thread // Class which mimics the std::thread
{
public:
// Implementation

// Checked exception thrown correctly

Thread() noexcept(false)
{
bool resourcesAvailable = false;
// ...
if (!resourcesAvailable)
{
throw std::system_error(
static_cast<int>(std::errc::resource_unavailable_try_again),
std::generic_category()); // Compliant - correct usage of
// checked exception system_error
}
}
};

See also

Effective Java: Item 58 - Use checked exceptions for recoverable conditions and runtime exceptions for programming errors.

Rule A15-0-6 (required, verification / toolchain, non-automated)An analysis shall be performed to analyze the failure modes of exception handling. In particular, the following failure modes shall be analyzed: (a) worst time execution time not existing or cannot be determined, (b) stack not correctly unwound, (c) exception not thrown, other exception thrown, wrong catch activated, (d) memory not available while exception handling.

Rationale

Note that the worst-case execution time and behavior of exception handling can be hardware specific. This rule requires only that the exception handling is deterministic in the sense that it has a deterministic behavior. Note: this analysis can be performed by the compiler supplier or it can be done by the project.


## See also
none
Rule A15-0-7 (required, verification / toolchain, partially automated)Exception handling mechanism shall guarantee a deterministic worstcase time execution time.
## Rationale
Compilers, i.e. GCC or Clang, uses dynamic memory allocation in order to allocate
currently thrown exception in their exception handling mechanism implementations.
This causes a non-deterministic execution time and run-time allocation errors. A
possible working approach is to modify the memory allocator so that the dynamic
memory does not need to be obtained (from OS) when an exception is thrown.
A static code analysis can search for a use of dynamic memory in the implementation of
the try/catch mechanism of the compiler, to show if worst-case time cannot be ensured.

GCC compiler uses following gcc library’s functions to provide exception handling
mechanism routines:
__cxa_allocate_exception
__cxa_throw
__cxa_free_exception
__cxa_begin_catch
__cxa_end_catch

Specific stack unwinding functions, i.e. _Unwind_RaiseException,
_Unwind_Resume, _Unwind_DeleteException, etc.

## Example
```cpp
//% $Id: A15-0-7.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <cstdlib>
#include <cstring>
struct CxaException
{
// Exception’s structure implementation
};
extern "C" void FatalError(const char* msg)

{
// Reports an error and terminates the program
}

extern "C" void* CxaAllocateExceptionDynamically(size_t thrownSize)

{
size_t size = thrownSize + sizeof(CxaException);
CxaException* buffer = static_cast<CxaException*>(

malloc(size)); // Non-compliant - dynamic memory allocation used

if (!buffer)
{
FatalError("Not enough memory to allocate exception!");
}

memset(buffer, 0, sizeof(CxaException));
return buffer + 1;
}
extern "C" void* StaticMalloc(size_t size)

{
void* mem = NULL;

// Allocates memory using static memory pool
return mem;
}
extern "C" void* CxaAllocateExceptionStatically(size_t thrownSize)

{
size_t size = thrownSize + sizeof(CxaException);
CxaException* buffer = static_cast<CxaException*>(StaticMalloc(

size)); // Compliant - memory allocation on static memory pool used

if (!buffer)
{
FatalError("Not enough memory to allocate exception!");
}

memset(buffer, 0, sizeof(CxaException));
return buffer + 1;
}

See also

none

Rule A15-0-8 (required, verification / toolchain, non-automated)A worst-case execution time (WCET) analysis shall be performed to determine maximum execution time constraints of the software, covering in particular the exceptions processing.

Rationale

Some systems require a guarantee that an action will be performed within predictable time constraints. Such real-time systems are allowed to use exception handling mechanism only if there is a tool support for accurate predicting such maximum time boundaries. “Before deciding that you cannot afford or don’t like exception-based error handling, have a look at the alternatives; they have their own complexities and problems. Also, as far as possible, measure before making claims about efficiency.” [C++ Core Guidelines]


## See also
MISRA C++ 2008 [7]: 15-0-1 (Document) Exceptions shall only be used for
error handling.
open-std.org [18]: ISO/IEC TR 18015:2006(E). Technical Report on C++
Performance

Rule A15-1-1 (advisory, implementation, automated)

Only instances of types derived from std::exception should be thrown.

Rationale

If an object that inherits from std::exception is thrown, there’s a guarantee that it serves to document the cause of an exception in an unified way. Also, "it makes your code easier to learn and re-use, because it matches established conventions with which programmers are already familiar.". [Effective Java 2nd Edition [15]] This means that only standard library exceptions or user-defined exceptions that inherit from std::exception base class should be used for exceptions. Note that direct instances of std::exception are not to be thrown as they can not be unique.

Example

//% $Id: A15-1-1.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <memory>
#include <stdexcept>
class A

{
// Implementation
};
class MyException : public std::logic_error
{
public:
using std::logic_error::logic_error;
// Implementation
};
void F1()
{
throw - 1; // Non-compliant - integer literal thrown
}
void F2()
{
throw nullptr; // Non-compliant - null-pointer-constant thrown
}
void F3()
{
throw A();
Non-compliant - user-defined type that does not inherit from
std::exception thrown
}
void F4()
{
throw std::logic_error{
"Logic Error"}; // Compliant - std library exception thrown
}
void F5()
{
throw MyException{"Logic Error"}; // Compliant - user-defined type that
// inherits from std::exception thrown
}
void F6()
{
throw std::make_shared<std::exception>(
std::logic_error("Logic Error")); // Non-compliant - shared_ptr does
// not inherit from std::exception
}
void F7()
{
try
{
F6();
}

catch (std::exception& e) // An exception of
// std::shared_ptr<std::exception> type will not
// be caught here

{
// Handle an exception
}

catch (std::shared_ptr<std::exception>& e) // An exception of
// std::shared_ptr<std::exception>
// type will be caught here, but
// unable to access
// std::logic_error information
{
// Handle an exception
}
}

See also

HIC++ v4.0 [9]: 15.1.1 Only use instances of std::exception for exceptions C++ Core Guidelines [11]: E.14: Use purpose-designed user-defined types as exceptions (not built-in types) Effective Java 2nd Edition [15]: Item 60: Favor the use of standard exceptions

Rule A15-1-2 (required, implementation, automated)

An exception object shall not be a pointer.

Rationale

If an exception object of pointer type is thrown and that pointer refers to a dynamically created object, then it may be unclear which function is responsible for destroying it, and when. This may lead to memory leak. If an exception object of pointer type is thrown and that pointer refers to an automatic variable, it allows using a variable after its destruction, leading to undefined behavior. This ambiguity does not exist if a copy of the object is thrown.

Example

//% $Id: A15-1-2.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <cstdint>
class A
{
// Implementation
};
void Fn(std::int16_t i)
{
A a1;
A& a2 = a1;
A* a3 = new A;

if (i < 10)
{
throw a1; // Compliant - copyable object thrown
}

else if (i < 20)
{
throw A(); // Compliant - copyable object thrown
}

else if (i < 30)
{
throw a2; // Compliant - copyable object thrown
}

else if (i < 40)
{
throw & a1; // Non-compliant - pointer type thrown
}

else if (i < 50)
{
throw a3; // Non-compliant - pointer type thrown
}

else if (i < 60)
{
throw(*a3); // Compliant - memory leak occurs, violates other rules

}

else
{
throw new A; // Non-compliant - pointer type thrown
}
}

See also

MISRA C++ 2008 [7]: 15-0-2 An exception object should not have pointer type. C++ Core Guidelines [11]: E.13: Never throw while being the direct owner of an object

Rule M15-0-3 (required, implementation, automated)

Control shall not be transferred into a try or catch block using a goto or a switch statement. See MISRA C++ 2008 [7]

Rule M15-1-1 (required, implementation, automated)

The assignment-expression of a throw statement shall not itself cause an exception to be thrown. See MISRA C++ 2008 [7]

Rule M15-1-2 (required, implementation, automated)

NULL shall not be thrown explicitly. See MISRA C++ 2008 [7]

Rule M15-1-3 (required, implementation, automated)

An empty throw (throw;) shall only be used in the compound statement of a catch handler. See MISRA C++ 2008 [7]

Rule A15-1-3 (advisory, implementation, automated)

All thrown exceptions should be unique.

Rationale

Defining unique exceptions in the project significantly simplifies debug process. An exception is considered to be unique if at least one of the following conditions is fulfilled: The type of the exception does not occur in any other place in the project The error message (i.e. message itself, error code, etc.) of the exception does not occur in any other place in the project

Example

//% $Id: A15-1-3.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <iostream>
#include <sstream>
#include <stdexcept>
#include <string>
static std::string ComposeMessage(const char* file,

const char* func,
std::int32_t line,
const std::string& message) noexcept

{
std::stringstream s;
s << "(" << file << ", " << func << ":" << line << "): " << message;

return s.str();
}
void F1()
{
// ...
throw std::logic_error("Error");
}
void F2()
{
// ...
throw std::logic_error("Error"); // Non-compliant - both exception type and
// error message are not unique
}
void F3()
{
// ...
throw std::invalid_argument(
"Error"); // Compliant - exception type is unique
}
void F4() noexcept(false)
{
// ...
throw std::logic_error("f3(): preconditions were not met"); // Compliant // error
// message is
// unique

}
void F5() noexcept(false)
{
// ...
throw std::logic_error(ComposeMessage(
__FILE__,
__func__,
__LINE__,
"postconditions were not met")); // Compliant - error message is unique
}
void F6() noexcept
{
try
{
F1();
F2();
F3();
}

catch (std::invalid_argument& e)
{
std::cout << e.what() << ’\n’; // Only f3() throws this type of
// exception, it is easy to deduce which
// function threw

}

catch (std::logic_error& e)
{
std::cout << e.what() << ’\n’; // f1() and f2() throw exactly the same
// exceptions, unable to deduce which
// function threw
}

try
{
F4();
F5();
}

catch (std::logic_error& e)
{
std::cout << e.what() << ’\n’; // Debugging process simplified, because
// of unique error message it is known
// which function threw
}
}

See also

Effective Java 2nd Edition [15]: Item 63: Include failure-capture information in detail messages

Rule A15-1-4 (required, implementation, partially automated)

If a function exits with an exception, then before a throw, the function shall place all objects/resources that the function constructed in valid states or it shall delete them.

Rationale

If the only handler to dynamically allocated memory or system resource (e.g. file, lock, network connection or thread) goes out of scope due to throwing an exception, memory leak occurs. Memory leaks lead to performance degradation, security violations and software crashes. Allocated memory or system resource can be released by explicit call to resource deinitialization or memory deallocation function (such as operator delete), before each return/try/break/continue statement. However, this solution is error prone and difficult to maintain. The recommended way of releasing dynamically allocated objects and resources is to follow RAII ("‘Resource Acquisition Is Initialization"’) design pattern, also known as Scope-Bound Resource Management or “Constructor Acquires, Destructor Releases” (CADRe). It allows to bind the life cycle of the resource to the lifetime of a scope-bound object. It guarantees that resources are properly deinitialized and released when data flow reaches the end of the scope.

Examples of RAII design pattern that significantly simplifies releasing objects/resources on throwing an exception are C++ smart pointers: std::unique_ptr and std::shared_ptr.

Example

//% $Id: A15-1-4.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <cstdint>
#include <memory>
#include <stdexcept>
extern std::uint32_t F1();
void FVeryBad() noexcept(false)
{
std::logic_error* e = new std::logic_error("Logic Error 1");

// ...
std::uint32_t i = F1();

if (i < 10)
{
throw(*e); // Non-compliant - fVeryBad() is not able to clean-up

// allocated memory

}

// ...
delete e;
}
void FBad() noexcept(false)
{
std::int32_t* x = new std::int32_t(0);

// ...
std::uint32_t i = F1();

if (i < 10)
{
throw std::logic_error("Logic Error 2"); // Non-compliant - exits from
// fBad()
without cleaning-up
// allocated resources and
// causes a memory leak

}

else if (i < 20)
{
throw std::runtime_error("Runtime Error 3"); // Non-compliant - exits
// from fBad()
without
// cleaning-up
allocated
// resources and causes a
// memory leak

}

// ...
delete x; // Deallocates claimed resource only in the end of fBad() scope
}

void FGood() noexcept(false)
{
std::int32_t* y = new std::int32_t(0);

// ...
std::uint32_t i = F1();

if (i < 10)
{
delete y; // Deletes allocated resource before throwing an exception
throw std::logic_error("Logic Error 4"); // Compliant - deleting y
// variable before exception
// leaves the fGood() scope

}

else if (i < 20)
{
delete y; // Deletes allocated resource before throwing an exception
throw std::runtime_error("Runtime Error 5"); // Compliant - deleting y
// variable before
// exception leaves the
// fGood() scope

}

else if (i < 30)
{
delete y; // Deletes allocated resource before throwing an exception
// again, difficult to maintain
throw std::invalid_argument(
"Invalid Argument 1"); // Compliant
- deleting
// y variable before
// exception
leaves the
// fGood() scope
}

// ...
delete y; // Deallocates claimed resource also in the end of fGood() scope
}
void FBest() noexcept(false)
{
std::unique_ptr<std::int32_t> z = std::make_unique<std::int32_t>(0);
// ...
std::uint32_t i = F1();

if (i < 10)
{
throw std::logic_error("Logic Error 6"); // Compliant - leaving the
// fBest() scope causes
// deallocation of all

// automatic variables, unique_ptrs, too
}

else if (i < 20)
{
throw std::runtime_error("Runtime Error 3"); // Compliant - leaving the
// fBest() scope causes
// deallocation
of all
// automatic variables,
// unique_ptrs,
too

}

else if (i < 30)
{
throw std::invalid_argument(
"Invalid Argument 2"); // Compliant - leaving the fBest() scope
// causes deallocation of all automatic
// variables, unique_ptrs,

// too
}

// ...
// z is deallocated automatically here, too
}
class CRaii // Simple class that follows RAII pattern
{
public:
CRaii(std::int32_t* pointer) noexcept : x(pointer) {}

~CRaii()
{
delete x;
x = nullptr;
}

private:
std::int32_t* x;

};
void FBest2() noexcept(false)
{
CRaii a1(new std::int32_t(10));
// ...
std::uint32_t i = F1();

if (i < 10)
{
throw std::logic_error("Logic Error 7"); // Compliant - leaving the
// fBest2()
scope causes a1
// variable
deallocation
// automatically

}
else if (i < 20)
{
throw std::runtime_error("Runtime Error 4"); // Compliant - leaving the
// fBest2() scope causes

Guidelines for the use of the C++14 language in
critical and safety-related systems
// a1 variable
// deallocation
// automatically

}
else if (i < 30)
{
throw std::invalid_argument(
"Invalid Argument 3"); // Compliant - leaving the fBest2() scope
// causes a1 variable deallocation
// automatically

}

// ...
// a1 is deallocated automatically here, too
}

See also

SEI CERT C++ [10]: ERR57-CPP. Do not leak resources when handling exceptions C++ Core Guidelines [11]: E.6: Use RAII to prevent leaks.

Rule A15-1-5 (required, implementation, non-automated)

Exceptions shall not be thrown across execution boundaries.

Rationale

An execution boundary is the delimitation between code compiled by differing compilers, including different versions of a compiler produced by the same vendor. For instance, a function may be declared in a header file but defined in a library that is loaded at runtime. The execution boundary is between the call site in the executable and the function implementation in the library. Such boundaries are also called ABI (application binary interface) boundaries because they relate to the interoperability of application binaries. Throwing an exception across an execution boundary requires that both sides of the execution boundary use the same ABI for exception handling, which may be difficult to ensure.

Exception

If it can be ensured that the execution boundaries use the same ABI for exception handling routines on both sides, then throwing an exception across these execution boundaries is allowed.


## See also
SEI CERT C++ [10]: ERR59-CPP. Do not throw an exception across execution
boundaries

Rule A15-2-1 (required, implementation, automated)

Constructors that are not noexcept shall not be invoked before program startup.

Rationale

Before the program starts executing the body of main function, it is in a start-up phase, constructing and initializing static objects. There is nowhere an exception handler can be placed to catch exceptions thrown during this phase, so if an exception is thrown it leads to the program being terminated in an implementation-defined manner.

Such errors may be more difficult to find because an error message can not be logged, due to lack of exception handling mechanism during static initialization.

Example

//% $Id: A15-2-1.cpp 271927 2017-03-24 12:01:35Z piotr.tanski $
#include <cstdint>
#include <stdexcept>
class A
{
public:
A() noexcept : x(0)
{
// ...
}
explicit A(std::int32_t n) : x(n)
{
// ...
throw std::runtime_error("Unexpected error");
}
A(std::int32_t i, std::int32_t j) noexcept : x(i + j)
{
try
{
// ...
throw std::runtime_error("Error");
// ...
}

catch (std::exception& e)
{
}
}

private:
std::int32_t x;
};

static A a1;
// Compliant - default constructor of type A is noexcept
static A a2(5); // Non-compliant - constructor of type A throws, and the
// exception will not be caught by the handler in main function
static A a3(5, 10); // Compliant - constructor of type A is noexcept, it
// handles exceptions internally

int main(int, char**)

{
try
{
// program code
}
catch (...)
{
// Handle exceptions
}

return 0;
}

See also

SEI CERT C++ [10]: ERR51-CPP. Handle all exceptions.

Rule A15-2-2 (required, implementation, partially automated)

If a constructor is not noexcept and the constructor cannot finish object initialization, then it shall deallocate the object’s resources and it shall throw an exception.

Rationale

Leaving the constructor with invalid object state leads to undefined behavior.

Example

//% $Id: A15-2-2.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <fstream>
#include <stdexcept>
class A
{
public:
A() = default;
};
class C1
{
public:
C1()
noexcept(false)
: a1(new A), a2(new A) // Non-compliant - if a2 memory allocation
// fails, a1 will never be deallocated

{

}
C1(A* pA1, A* pA2)

noexcept : a1(pA1), a2(pA2) // Compliant - memory allocated outside of C1
// constructor, and no exceptions can be thrown
{
}

private:
A* a1;
A* a2;

};
class C2
{
public:
C2() noexcept(false) : a1(nullptr), a2(nullptr)
{
try
{
a1 = new A;
a2 = new A; // If memory allocation for a2 fails, catch-block will
// deallocate a1
}

catch (std::exception& e)
{
throw; // Non-compliant
// exception, a1

- whenever
will never

a2 allocation throws an
be deallocated

}
}

private:
A* a1;
A* a2;

};
class C3
{
public:
C3() noexcept(false) : a1(nullptr), a2(nullptr), file("./filename.txt")
{
try
{
a1 = new A;
a2 = new A;

if (!file.good())
{
throw std::runtime_error("Could not open file.");
}

}

catch (std::exception& e)

{
delete a1;
a1 = nullptr;
delete a2;
a2 = nullptr;
file.close();
throw; //
//

Compliant - all resources are deallocated before the
constructor exits with an exception

}
}

private:
A* a1;
A* a2;

std::ofstream file;
};
class C4
{
public:
C4() : x(0), y(0)
{
// Does not need to check preconditions here - x and y initialized with
// correct values
}
C4(std::int32_t first, std::int32_t second)
noexcept(false) : x(first), y(second)
{
CheckPreconditions(x,
y); // Compliant - if constructor failed to create a
// valid object, then throw an exception
}
static void CheckPreconditions(std::int32_t x,
std::int32_t y) noexcept(false)
{
if (x < 0 || x > 1000)
{
throw std::invalid_argument(
"Preconditions of class C4 were not met");
}

else if (y < 0 || y > 1000)
{
throw std::invalid_argument(
"Preconditions of class C4 were not met");
}
}

private:
std::int32_t x; // Acceptable range: <0; 1000>
std::int32_t y; // Acceptable range: <0; 1000>
};

See also

C++ Core Guidelines [11]: C.42: If a constructor cannot construct a valid object, throw an exception

Rule M15-3-1 (required, implementation, automated)

Exceptions shall be raised only after start-up and before termination. See MISRA C++ 2008 [7]

Rule A15-3-2 (required, implementation, non-automated)

If a function throws an exception, it shall be handled when meaningful actions can be taken, otherwise it shall be propagated.

Rationale

Provide exception handlers only for functions that actually are able to take recovery or cleanup actions. Implementing meaningless exception handlers that only re-throw caught exception results in an implementation that is inefficient and difficult to maintain.

Example

//% $Id: A15-3-2.cpp 309502 2018-02-28 09:17:39Z michal.szczepankiewicz $
#include <cstdint>
#include <iostream>
#include <stdexcept>
#include <memory>

/// @checkedException
class CommunicationError : public std::exception
{
// Implementation
};

/// @throw CommunicationError Exceptional communication errors
extern void Send(std::uint8_t* buffer) noexcept(false);

void SendData1(std::uint8_t* data) noexcept(false)

{
try
{
Send(data);
}

catch (CommunicationError& e)

{
std::cerr << "Communication error occured" << std::endl;
throw; // Non-compliant - exception is not handled, just re-thrown
}
}
extern void BusRestart() noexcept;
extern void BufferClean() noexcept;
void SendData2(std::uint8_t* data) noexcept(false)

{
try
{
Send(data);
}

catch (CommunicationError& e)
{
std::cerr << "Communication error occured" << std::endl;
BufferClean();
throw; // Compliant - exception is partially handled and re-thrown
}
}
void F1() noexcept
{
std::uint8_t* buffer = nullptr;

// ...
try
{
SendData2(buffer);
}

catch (CommunicationError& e)
{
std::cerr << "Communication error occured" << std::endl;
BusRestart();
// Compliant - including SendData2() exception handler, exception is now
// fully handled
}
}
void SendData3(std::uint8_t* data) noexcept

{
try
{
Send(data);
}

catch (CommunicationError& e)
{
std::cerr << "Communication error occured" << std::endl;
BufferClean();
BusRestart();

// Compliant - exception is fully handled
}
}

struct A
{
std::uint32_t x;
};

std::unique_ptr<A[]> Func1()
{
//rather throws std::bad_alloc
return std::make_unique<A[]>(999999999999999999);
}

std::unique_ptr<A[]> Func2()
{
//does not catch std::bad_alloc
//because nothing meaningful can be done here
return Func1();
}

std::unique_ptr<A[]> Func3()
{
//does not catch std::bad_alloc
//because nothing meaningful can be done here
return Func2();
}

extern void Cleanup() noexcept;

int main(void)
{
try
{
Func3();
}
catch (const std::exception& ex)
{
//catches std::bad_alloc here and
//terminates the application
//gracefully
Cleanup();
}

return 0;
}

See also

none

Rule A15-3-3 (required, implementation, partially-automated)

Main function and a task main function shall catch at least: base class exceptions from all third-party libraries used, std::exception and all otherwise unhandled exceptions.

Rationale

If a program throws an unhandled exception in main function, as well as in init thread function, the program terminates in an implementation-defined manner. In particular, it is implementation-defined whether the call stack is unwound, before termination, so the destructors of any automatic objects may or may not be executed. By enforcing the provision of a “last-ditch catch-all”, the developer can ensure that the program terminates in a consistent manner. Exceptions hierarchy from external libraries may be completely separate from C++ Standard Library std::exception. Handling such base exception classes separately may provide some additional information about application termination causes.

Example

//% $Id: A15-3-3.cpp 309502 2018-02-28 09:17:39Z michal.szczepankiewicz $
#include <stdexcept>

//base exception class from external library that is used
class ExtLibraryBaseException {};

int MainGood(int, char**) // Compliant

{
try
{
// program code
}
catch (std::runtime_error& e)
{
// Handle runtime errors
}
catch (std::logic_error& e)
{
// Handle logic errors
}
catch (ExtLibraryBaseException &e)
{
// Handle all expected exceptions
// from an external library
}
catch (std::exception& e)
{
// Handle all expected exceptions
}
catch (...)
{

// Handle all unexpected exceptions
}

return 0;
}
int MainBad(int, char**) // Non-compliant - neither unexpected exceptions

// nor external libraries exceptions are caught

{
try
{
// program code
}
catch (std::runtime_error& e)
{
// Handle runtime errors
}
catch (std::logic_error& e)
{
// Handle logic errors
}
catch (std::exception& e)
{
// Handle all expected exceptions
}

return 0;
}
void ThreadMainGood() // Compliant
{
try
{
// thread code
}
catch (ExtLibraryBaseException &e)
{
// Handle all expected exceptions
// from an external library
}
catch (std::exception& e)
{
// Handle all expected exception
}
catch (...)
{
// Handle all unexpected exception
}
}

void ThreadMainBad()

// Non-compliant - neither unexpected exceptions
// nor external libraries exceptions are caught

{

try
{
// thread code
}
catch (std::exception& e)
{
// Handle all expected exceptions
}

// Uncaught unexpected exception will cause an immediate program termination
}

See also

MISRA C++ 2008 [7]: 15-3-2 There should be at least one exception handler to catch all otherwise unhandled exceptions. SEI CERT C++ [10]: ERR51-CPP. Handle all exceptions Effective Java 2nd Edition [15]: Item 65: Don’t ignore exceptions Rule A15-3-4 (required, implementation, non-automated) Catch-all (ellipsis and std::exception) handlers shall be used only in (a) main, (b) task main functions, (c) in functions that are supposed to isolate independent components and (d) when calling third-party code that uses exceptions not according to AUTOSAR C++14 guidelines.

Rationale

Catching an exception through catch-all handlers does not provide any detailed information about caught exception. This does not allow to take meaningful actions to recover from an exception other than to re-throw it. This is inefficient and results in code that is difficult to maintain.

Example

//% $Id: A15-3-4.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <stdexcept>
#include <thread>
extern std::int32_t Fn(); // Prototype of external third-party library function
void F1() noexcept(false)
{
try
{
std::int32_t ret = Fn();
// ...
}

// ...
catch (...) // Compliant

{
// Handle all unexpected exceptions from fn() function
}
}
void F2() noexcept(false)
{
std::int32_t ret =
Fn(); // Non-compliant - can not be sure whether fn() throws or not

if (ret < 10)
{
throw std::underflow_error("Error");
}

else if (ret < 20)
{
// ...
}
else if (ret < 30)
{
throw std::overflow_error("Error");
}

else
{
throw std::range_error("Error");
}
}
void F3() noexcept(false)
{
try
{
F2();
}

catch (std::exception& e) // Non-compliant - caught exception is too
// general, no information which error occured
{
// Nothing to do
throw;
}
}
void F4() noexcept(false)
{
try
{
F3();
}

catch (...) // Non-compliant - no information about the exception
{

// Nothing to do
throw;
}
}
class ExecutionManager
{
public:
ExecutionManager() = default;
void Execute() noexcept(false)
{
try
{
F3();
}

// ...
catch (std::exception& e) // Compliant
{
// Handle all expected exceptions
}
catch (...) // Compliant
{
// Handle all unexpected exceptions
}
}
};
void ThreadMain() noexcept
{
try
{
F3();
}

// ...
catch (std::exception& e) // Compliant
{
// Handle all expected exceptions
}
catch (...) // Compliant
{
// Handle all unexpected exceptions
}
}
int main(int, char**)

{
try
{
ExecutionManager execManager;
execManager.Execute();
// ...
std::thread t(&ThreadMain);

// ...
F4();
}

// ...
catch (std::exception& e) // Compliant
{
// Handle all expected exceptions
}
catch (...) // Compliant
{
// Handle all unexpected exceptions
}

return 0;
}

See also

none

Rule M15-3-3 (required, implementation, automated)

Handlers of a function-try-block implementation of a class constructor or destructor shall not reference non-static members from this class or its bases. See MISRA C++ 2008 [7]

Rule M15-3-4 (required, implementation, automated)

Each exception explicitly thrown in the code shall have a handler of a compatible type in all call paths that could lead to that point. See MISRA C++ 2008 [7]

Rule A15-3-5 (required, implementation, automated)

A class type exception shall be caught by reference or const reference.

Rationale

If a class type exception object is caught by value, slicing occurs. That is, if the exception object is of a derived class and is caught as the base, only the base class’s functions (including virtual functions) can be called. Also, any additional member data in the derived class cannot be accessed. If the exception is caught by reference or const reference, slicing does not occur.

Example

//% $Id: A15-3-5.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <iostream>
#include <stdexcept>
class Exception : public std::runtime_error
{
public:
using std::runtime_error::runtime_error;
const char* what() const noexcept(true) override

{
return "Exception error message";
}
};
void Fn()
{
try
{
// ...
throw std::runtime_error("Error");
// ...
throw Exception("Error");
}

catch (const std::logic_error& e) // Compliant - caught by const reference
{
// Handle exception
}
catch (std::runtime_error& e) // Compliant - caught by reference
{
std::cout << e.what() << "\n"; // "Error" or "Exception error message"
// will be printed, depending upon the
// actual type of thrown object
throw e; // The exception re-thrown is of its original type
}

catch (
std::runtime_error
e)

// Non-compliant - derived types will be caught as the base type

{
std::cout
<< e.what()
<< "\n"; // Will always call what() method from std::runtime_error
throw e; // The exception re-thrown is of the std::runtime_error type,
// not the original exception type
}
}

See also

MISRA C++ 2008 [7]: 15-3-5 A class type exception shall always be caught by reference. SEI CERT C++ [10]: ERR61-CPP. Catch exceptions by lvalue reference

C++ Core Guidelines [11]: E.15: Catch exceptions from a hierarchy by reference

Rule M15-3-6 (required, implementation, automated)

Where multiple handlers are provided in a single try-catch statement or function-try-block for a derived class and some or all of its bases, the handlers shall be ordered most-derived to base class. See MISRA C++ 2008 [7]

Rule M15-3-7 (required, implementation, automated)

Where multiple handlers are provided in a single try-catch statement or function-try-block, any ellipsis (catch-all) handler shall occur last. See MISRA C++ 2008 [7]

Rule A15-4-1 (required, implementation, automated)

Dynamic exception-specification shall not be used.

Rationale

This feature was deprecated in the 2011 C++ Language Standard (See: Deprecating Exception Specifications). Main issues with dynamic exception specifications are: Run-time checking: Exception specifications are checked at runtime, so the program does not guarantee that all exceptions will be handled. The run-time failure mode does not lend itself to recovery. Run-time overhead: Run-time checking requires the compiler to produce additional code that hampers optimizations. Unusable in generic code: It is not possible to know what types of exceptions may be thrown from templates arguments operations, so a precise exception specification cannot be written. In place of dynamic exception-specification, use noexcept specification that allows to declare whether a function throws or does not throw exceptions. Note: std::unexpected_handler shall not be used.

Example

//% $Id: A15-4-1.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <stdexcept>
void F1() noexcept; // Compliant - note that noexcept is the same as
// noexcept(true)
void F2() throw();
// Non-compliant - dynamic exception-specification is
// deprecated
void F3() noexcept(false);
// Compliant
void F4() throw(std::runtime_error); // Non-compliant - dynamic
// exception-specification is deprecated
void F5() throw(
...); // Non-compliant - dynamic exception-specification is deprecated
template <class T>
void F6() noexcept(noexcept(T())); // Compliant

See also

C++ Core Guidelines [11]: E.12: Use noexcept when exiting a function because of a throw is impossible or unacceptable open-std.org [18]: open std Deprecating Exception Specifications mill22: A Pragmatic Look at Exception Specifications

Rule A15-4-2 (required, implementation, automated)

If a function is declared to be noexcept, noexcept(true) or noexcept(), then it shall not exit with an exception.

Rationale

If a function declared to be noexcept, noexcept(true) or noexcept(true condition) throws an exception, then std::terminate() is called immediately. It is implementationdefined whether the call stack is unwound before std::terminate() is called. To ensure that the rule is not violated, if function’s noexcept specification can not be determined, then always declare it to be noexcept(false).

Example

//% $Id: A15-4-2.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
2 #include <stdexcept>
// library.h
void LibraryFunc();
// project.cpp
void F1() noexcept
{
// ...
Non-compliant - f1 declared to be
throw std::runtime_error("Error");
noexcept, but exits with exception.
This leads to std::terminate() call
}
void F2() noexcept(true)

{
try
{
// ...
throw std::runtime_error(
"Error");
// Compliant - exception will not leave f2
}
catch (std::runtime_error& e)
{
// Handle runtime error
}
}
void F3() noexcept(false)
{
// ...
throw std::runtime_error("Error"); // Compliant
}
void F4() noexcept(
false) // Compliant - no information whether library_func() throws or not
{
LibraryFunc();
}

See also

MISRA C++ 2008 [7]: 15-5-2: Where a function’s declaration includes an exception-specification, the function shall only be capable of throwing exceptions of the indicated type(s). MISRA C++ 2008 [7]: 15-5-3: The terminate() function shall not be called implicitly. HIC++ v4.0 [9]: 15.3.2: Ensure that a program does not result in a call to std::terminate SEI CERT C++ Coding Standard [10]: ERR50-CPP: Do not abruptly terminate the program.

Rule A15-4-3 (required, implementation, automated)

The noexcept specification of a function shall either be identical across all translation units, or identical or more restrictive between a virtual member function and an overrider.

Rationale

Declarations of the same function, even in different translation units, have to specify the same noexcept specification. Overriding functions have to specify the same or a stricter noexcept specification than the base class function which they override.

Note that in many cases, a violation of this rule will lead to a compilation error. This is not guaranteed, however, in particular when function declarations appear in separate translation units.

Example

//% $Id: A15-4-3.cpp 317753 2018-04-27 07:44:02Z jan.babst $
// f1.hpp
void Fn() noexcept;

// f1.cpp
// #include <f1.hpp>
void Fn() noexcept // Compliant
{
// Implementation
}

// f2.cpp
// #include <f1.hpp>
void Fn() noexcept(false) // Non-compliant - different exception specifier
{
// Implementation
}

class A
{
public:
void F() noexcept;
void G() noexcept(false);
virtual void V1() noexcept = 0;
virtual void V2() noexcept(false) = 0;
};
void A::F() noexcept // Compliant
// void A::F() noexcept(false) // Non-compliant - different exception specifier
// than in declaration
{
// Implementation
}
void A::G() noexcept(false) // Compliant
// void A::G() noexcept // Non-compliant - different exception specifier than
// in declaration
{
// Implementation
}
class B : public A
{
public:
void V1() noexcept override // Compliant
// void V1() noexcept(false) override // Non-compliant - less restrictive
// exception specifier in derived method, non-compilable
{
// Implementation

}
void V2() noexcept override // Compliant - stricter noexcept specification
{
// Implementation
}
};

See also

MISRA C++ 2008 [7]: 15-4-1: If a function is declared with an exceptionspecification, then all declarations of the same function (in other translation units) shall be declared with the same set of type-ids.

Rule A15-4-4 (required, implementation, automated)

A declaration of non-throwing function shall contain noexcept specification.

Rationale

Noexcept specification is a method for a programmer to inform the compiler whether or not a function should throw exceptions. The compiler can use this information to enable certain optimizations on non-throwing functions as well as enable the noexcept operator, which can check at compile time if a particular expression is declared to throw any exceptions. Noexcept specification is also a method to inform other programmers that a function does not throw any exceptions. A non-throwing function needs to declare noexcept specifier. A function that may or may not throw exceptions depending on a template argument, needs to explicitly specify its behavior using noexcept() specifier. Note that it is assumed that a function which does not contain explicit noexcept specification throws exceptions, similarly to functions that declare noexcept(false) specifier.

Example

//% $Id: A15-4-4.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <iostream>
#include <stdexcept>
void F1(); // Compliant - f1, without noexcept specification, declares to throw
// exceptions implicitly
void F2() noexcept;
// Compliant - f2
does not throw exceptions
void
F3()
noexcept(true);
//
Compliant
f3
does not throw exceptions
void F4() noexcept(false); // Compliant - f4 declares to throw exceptions
9 void F5() noexcept
// Compliant - f5 does not throw exceptions
{
try
{

F1(); // Exception handling needed, f1 has no noexcept specification
}

catch (std::exception& e)
{
// Handle exceptions
}

F2(); // Exception handling not needed, f2 is noexcept
F3(); // Exception handling not needed, f3 is noexcept(true)

try
{
F4(); // Exception handling needed, f4 is noexcept(false)
}

catch (std::exception& e)
{
// Handle exceptions
}
}
template <class T>
void F6() noexcept(noexcept(T())); // Compliant - function f6() may be
// noexcept(true) or noexcept(false)
// depending on constructor of class
template <class T>
class A
{
public:
A() noexcept(noexcept(T())) // Compliant - constructor of class A may be
// noexcept(true) or noexcept(false) depending on
// constructor of class T
{
}
};
class C1
{
public:
C1()
noexcept(
true) // Compliant - constructor of class C1 does not throw exceptions
{
}
// ...
};
class C2
{
public:
C2() // Compliant - constructor of class C2 throws exceptions
{
}

T

// ...
};
void F7() noexcept // Compliant - f7 does not throw exceptions
{
std::cout << noexcept(A<C1>()) << ’\n’;
// prints ’1’ - constructor of
// A<C1> class is noexcept(true)
// because constructor of C1 class
// is declared to be noexcept(true)
std::cout << noexcept(A<C2>()) << ’\n’;
// prints ’0’ - constructor of
// A<C2> class is noexcept(false)
// because constructor of C2 class
// has no noexcept specifier

}

See also

none

Rule A15-4-5 (required, implementation, automated)

Checked exceptions that could be thrown from a function shall be specified together with the function declaration and they shall be identical in all function declarations and for all its overriders.

Rationale

In C++ language, all exceptions are unchecked, because the compiler does not force to either handle the exception or specify it. Because dynamic-exception specification is obsolete and error prone, an alternative mechanism of specifying checked exceptions using C++ comments along with function declarations is used. It is a concept that is based on Java exception handling mechanism. When analyzing a given function f, a static code analysis needs to analyze functions invoked by f and analyze if they throw any checked exceptions that are not caught by f and not listed by f in the function comment.

Exception

Within generic code, it is not generally possible to know what types of exceptions may be thrown from operations on template arguments, so a precise exception specification cannot be written. Therefore, this rule does not apply for templates.

Example

//% $Id: A15-4-5.cpp 309502 2018-02-28 09:17:39Z michal.szczepankiewicz $
#include <cstdint>
#include <stdexcept>

/// @checkedException
class CommunicationError : public std::exception
{

// Implementation
};
/// @checkedException
class BusError : public CommunicationError
{
// Implementation
};
/// @checkedException
class Timeout : public std::runtime_error
{
public:
using std::runtime_error::runtime_error;
// Implementation
};
/// @throw CommunicationError Communication error
/// @throw BusError Bus error
/// @throw Timeout
On send timeout exception
void Send1(
std::uint8_t* buffer,

std::uint8_t bufferLength) noexcept(false) // Compliant - All and only
// those checked exceptions
// that can be thrown are
// specified
{
// ...
throw CommunicationError();
// ...
throw BusError();
// ...
throw Timeout("Timeout reached");
// ...
}
/// @throw CommunicationError Communication error
void Send2(
std::uint8_t* buffer,

std::uint8_t bufferLength) noexcept(false) // Non-compliant - checked
// exceptions
// thrown are
// specification
{
// ...
throw CommunicationError();
// ...
throw Timeout("Timeout reached");
// ...
}
class MemoryPartitioningError : std::exception
{
// Implementation
};
/// @throw CommunicationError Communication error

that can be
missing from

/// @throw BusError Bus error
/// @throw Timeout
On send timeout exception
/// @throw MemoryPartitioningError Memory partitioning error prevents message
/// from being sent.
void Send3(

std::uint8_t* buffer,

std::uint8_t bufferLength) noexcept(false) // Non-compliant - additional
// checked exceptions are
// specified
{
// ...
throw CommunicationError();
// ...
throw Timeout("Timeout reached");
// ...
}

See also

Effective Java 2nd Edition [15]: Item 62: Document all exceptions thrown by each method

Rule A15-5-1 (required, implementation, automated)

All user-provided class destructors, deallocation functions, move constructors, move assignment operators and swap functions shall not exit with an exception. A noexcept exception specification shall be added to these functions as appropriate.

Rationale

When an exception is thrown, the call stack is unwound up to the point where the exception is to be handled. The destructors for all automatic objects declared between the point where the exception is thrown and where it is to be handled will be invoked. If one of these destructors or delete operators exits with an exception, then the program will terminate in an implementation-defined manner. Move constructors and move assignment operators are usually expected to be nonthrowing. If they throw exceptions, strong exception safety cannot be guaranteed, because the original type values could be already modified or partially modified. Note that some operations in the standard library statically check the noexcept specification of the move constructors and move assignment operators of parameter types. They may choose less efficient algorithms or provide fewer exception safety guarantees if these are not noexcept.

The standard-library containers and algorithms will not work correctly if swapping of two elements exits with an exception. A non-throwing swap function is also an important basic tool to implement the strong exception safety guarantee in a copy assignment operator (see A12-8-2). Note that it is acceptable for a destructor or deallocation function to throw an exception that is handled within this function, for example within a try-catch block. Note that deallocation functions are declared noexcept by default. A destructor is declared as noexcept by default unless a destructor of any base class or member is potentially-throwing. Using a base class or member with a potentially-throwing destructor is a violation of this rule. The respective base class or member destructor must be fixed in order to comply to this rule. The intention of this rule is that the implementation of a user-provided destructor is ensured to not exit with an exception. Only then, the default noexcept specification added implicitly to the user-provided destructor is correct. It may be explicitly restated as noexcept for documentation purposes. The compiler also adds a noexcept specification implicitly for any defaulted special member function. This noexcept specification depends on the noexcept specification of the member and base class operations that the defaulted special member function will call implicitly. It is therefore not required to default a special member function only to add the noexcept specification. Reasons to default a special member function exist independently from this rule, for example due to A12-0-1.

Exception

Generic move constructors, generic move assignment operators, and generic swap functions may have noexcept specifications which depend on type properties of the template parameters.

Example

//% $Id: A15-5-1.cpp 309720 2018-03-01 14:05:17Z jan.babst $
#include <stdexcept>
#include <type_traits>

class C1
{
public:
C1() = default;

// Compliant - move constructor is non-throwing and declared to be noexcept
C1(C1&& rhs) noexcept {}

// Compliant - move assignment operator is non-throwing and declared to be
// noexcept
C1& operator=(C1&& rhs) noexcept { return *this; }

// Compliant - destructor is non-throwing and declared to be noexcept by
// default

~C1() noexcept {}
};

void Swap(C1& lhs,
C1& rhs) noexcept // Compliant - swap function is non-throwing and
// declared to be noexcept
{
// Implementation
}

class C2
{
public:
C2() = default;

// Compliant - move constructor is non-throwing and declared to be noexcept
C2(C2&& rhs) noexcept
{
try
{
// ...
throw std::runtime_error(
"Error"); // Exception will not escape this function
}

catch (std::exception& e)
{
// Handle error
}
}

C2& operator=(C2&& rhs) noexcept
{
try
{
// ...
throw std::runtime_error(
"Error"); // Exception will not escape this function
}

catch (std::exception& e)
{
// Handle error
}
return *this;

}

// Compliant - destructor is non-throwing and declared to be noexcept by
// default
~C2()
{

try
{
// ...
throw std::runtime_error(
"Error"); // Exception will not escape this function

}

catch (std::exception& e)
{
// Handle error
}
}
};

// Non-compliant - swap function is declared to be noexcept(false)
void Swap(C2& lhs, C2& rhs) noexcept(false)
{
// ...
// Non-compliant - Implementation exits with an exception
throw std::runtime_error("Swap function failed");
}

class C3
{
public:
C3() = default;
C3(C3&& rhs) // Non-compliant - move constructor throws
{
// ...
throw std::runtime_error("Error");
}
C3& operator=(C3&& rhs) // Non-compliant - move assignment operator throws
{
// ...
throw std::runtime_error("Error");
return *this;

}
~C3() // Non-compliant - destructor exits with an exception
{
throw std::runtime_error("Error");
}
static void operator delete(void* ptr, std::size_t sz)

{
// ...
throw std::runtime_error("Error"); // Non-compliant - deallocation
// function exits with an exception
}
};

void Fn()
{

C3 c1; // program terminates when c1 is destroyed
C3* c2 = new C3;

// ...
delete c2; // program terminates when c2 is deleted
}

template <typename T>
class Optional
{
public:
// ...

// Compliant by exception
Optional(Optional&& other) noexcept(
std::is_nothrow_move_constructible<T>::value)
{
// ...
}

// Compliant by exception
Optional& operator=(Optional&& other) noexcept(
std::is_nothrow_move_assignable<T>::value&&
std::is_nothrow_move_constructible<T>::value)
{
// ...
return *this;

}

// ...
};

See also

MISRA C++ 2008 [7]: 15-5-1: A class destructor shall not exit with an exception. HIC++ v4.0 [9]: 15.2.1: Do not throw an exception from a destructor C++ Core Guidelines [11]: E.16: Destructors, deallocation, and swap must never fail C++ Core Guidelines [11]: C.85: Make swap noexcept ISO/IEC 14882:2014 [3]: 15.4: [except.spec] ISO/IEC 14882:2014 [3]: 20.2.4, paragraph 9: [forward] A12-0-1 in section 6.12.0 A12-8-2 in section 6.12.8 Rule A15-5-2 (required, implementation, partially automated) Program shall not be abruptly terminated. In particular, an implicit or

explicit invocation of std::abort(), std::quick_exit(), std::_Exit(), std::terminate() shall not be done.

Rationale

Functions that are used to terminate the program in an immediate fashion, i.e. std::abort(), std::quick_exit(), std::_Exit(), do so without calling exit handlers or calling destructors of automatic, thread or static storage duration objects. It is implementation-defined whether opened streams are flushed and closed, and temporary files are removed. The std::terminate() function calls std::abort() implicitly in its terminate handler, and it is implementation-defined whether or not stack unwinding will occur. Note: std::terminate_handler shall not be used.

Example

//% $Id: A15-5-2.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <cstdlib>
#include <exception>
void F1() noexcept(false);
void F2() // Non-compliant
{
F1(); // A call to throwing f1() may result in an implicit call to
// std::terminate()
}
void F3() // Compliant
{
try
{
F1(); // Handles all exceptions from f1() and does not re-throw
}
catch (...)
{
// Handle an exception
}
}
void F4(const char* log)

{
// Report a log error
// ...
std::exit(0); // Call std::exit() function which safely cleans up resources
}
void F5() // Compliant by exception
{
try
{
F1();
}
catch (...)
{

F4("f1() function failed");
}
}
int main(int, char**)

{
if (std::atexit(&F2) != 0)
{
// Handle an error
}

if (std::atexit(&F3) != 0)
{
// Handle an error
}

// ...
return 0;
}

See also

MISRA C++ 2008 [7]: 15-5-3 (Required) The terminate() function shall not be called implicitly. HIC++ v4.0 [9]: 15.3.2 Ensure that a program does not result in a call to std::terminate SEI CERT C++ [10]: ERR50-CPP. Do not abruptly terminate the program

Rule A15-5-3 (required, implementation, automated)

The std::terminate() function shall not be called implicitly.

Rationale

It is implementation-defined whether the call stack is unwound before std::terminate() is called. There is no guarantee that the destructors of automatic thread or static storage duration objects will be called. These are following ways to call std::terminate() function implicitly, according to (std::terminate() in CppReference [16]): an exception is thrown and not caught (it is implementation-defined whether any stack unwinding is done in this case) an exception is thrown during exception handling (e.g. from a destructor of some local object, or from a function that had to be called during exception handling)

the constructor or the destructor of a static or thread-local object throws an exception a function registered with std::atexit or std::at_quick_exit throws an exception

a noexcept specification is violated (it is implementation-defined whether any stack unwinding is done in this case) a dynamic exception specification is violated and the default handler for std::unexpected is executed a non-default handler for std::unexpected throws an exception that violates the previously violated dynamic exception specification, if the specification does not include std::bad_exception std::nested_exception::rethrow_nested is called for an object that isn’t holding a captured exception an exception is thrown from the initial function of std::thread a joinable std::thread is destroyed or assigned to Note: std::terminate_handler shall not be used.

Example

//% $Id: A15-5-3.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <stdexcept>
#include <thread>
extern bool F1();
class A
{
public:
A() noexcept(false)
{
// ...
throw std::runtime_error("Error1");
}
~A()
{
// ...
throw std::runtime_error("Error2"); // Non-compliant - std::terminate()
// called on throwing an exception
// from noexcept(true) destructor
}
};
class B
{
public:
~B() noexcept(false)
{
// ...
throw std::runtime_error("Error3");
}
};
void F2()
{
throw;

}
void ThreadFunc()
{
A a; // Throws an exception from a’s constructor and does not handle it in
// thread_func()
}
void F3()
{
try
{
std::thread t(&ThreadFunc); // Non-compliant - std::terminate() called
// on throwing an exception from
// thread_func()

if (F1())
{
throw std::logic_error("Error4");

}

else
{
F2(); // Non-compliant - std::terminate()
// active exception to be re-thrown

called if there is no
by f2

}
}
catch (...)
{
B b; // Non-compliant - std::terminate() called on throwing an
// exception from b’s destructor during exception handling

// ...
F2();
}
}
static A a; // Non-compliant - std::terminate() called on throwing an exception
// during program’s start-up phase
int main(int, char**)

{
F3(); // Non-compliant - std::terminate() called if std::logic_error is
// thrown
return 0;
}

See also

MISRA C++ 2008 [7]: 15-5-3 (Required) The terminate() function shall not be called implicitly.

Rule A16-0-1 (required, implementation, automated)

The pre-processor shall only be used for unconditional and conditional file inclusion and include guards, and using the following directives: (1) #ifndef, #ifdef, (3) #if, (4) #if defined, (5) #elif, (6) #else, (7) #define, (8) #endif, (9) #include.

Rationale

C++ provides safer, more readable and easier to maintain ways of achieving what is often done using the pre-processor. The pre-processor does not obey the linkage, lookup and function call semantics. Instead, constant objects, constexprs, inline functions and templates are to be used.

Example

// $Id: A16-0-1.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#pragma once // Non-compliant - implementation-defined feature

#ifndef HEADER_FILE_NAME // Compliant - include guard
#define HEADER_FILE_NAME // Compliant - include guard

#include <cstdint> // Compliant - unconditional file inclusion

#ifdef WIN32
#include <windows.h> // Compliant - conditional file inclusion
#endif

#ifdef WIN32
std::int32_t fn1(
std::int16_t x,
std::int16_t y) noexcept; // Non-compliant - not a file inclusion
#endif

#if defined VERSION && VERSION > 2011L // Compliant
#include <array>
// Compliant - conditional file inclusion
#elif VERSION > 1998L // Compliant
// Compliant
- conditional file inclusion
22 #include <vector>
// Compliant
23 #endif

#define MAX_ARRAY_SIZE 1024U // Non-compliant
#ifndef MAX_ARRAY_SIZE
// Non-compliant
#error "MAX_ARRAY_SIZE has not been defined" // Non-compliant
#endif
// Non-compliant
#undef MAX_ARRAY_SIZE // Non-compliant

#define MIN(a, b) (((a) < (b)) ? (a) : (b)) // Non-compliant

#define PLUS2(X) ((X) + 2) // Non-compliant - function should be used instead
#define PI 3.14159F// Non-compliant - constexpr should be used instead
#define std ::int32_t long // Non-compliant - ’using’ should be used instead
#define STARTIF if( // Non-compliant - language redefinition
#define HEADER "filename.h" // Non-compliant - string literal

void Fn2() noexcept
{
#ifdef __linux__ // Non-compliant - ifdef not used for file inclusion

// ...

#elif WIN32 // Non-compliant - elif not used for file inclusion

// ...

#elif __APPLE__ // Non-compliant - elif not used for file inclusion

// ...

#else // Non-compliant - else not used for file inclusion

// ...

#endif // Non-compliant - endif not used for file inclusion or include guards
}

#endif // Compliant - include guard

See also

MISRA C++ 2008 [7]: Rule 16-2-1 The pre-processor shall only be used for file inclusion and include guards. MISRA C++ 2008 [7]: Rule 16-2-2 C++ macros shall only be used for: include guards, type qualifiers, or storage class specifiers. JSF December 2005 [8]: AV Rule 26 Only the following pre-processor directives shall be used: 1. #ifndef 2. #define 3. #endif 4. #include. JSF December 2005 [8]: AV Rule 27 #ifndef, #define and #endif will be used to prevent multiple inclusions of the same header file. Other techniques to prevent the multiple inclusions of header files will not be used. JSF December 2005 [8]: AV Rule 28 The #ifndef and #endif pre-processor directives will only be used as defined in AV Rule 27 to prevent multiple inclusions of the same header file. JSF December 2005 [8]: AV Rule 29 The #define pre-processor directive shall not be used to create inline macros. Inline functions shall be used instead.

JSF December 2005 [8]: AV Rule 30 The #define pre-processor directive shall not be used to define constant values. Instead, the const qualifier shall be applied to variable declarations to specify constant values. JSF December 2005 [8]: AV Rule 31 The #define pre-processor directive will only be used as part of the technique to prevent multiple inclusions of the same header file. JSF December 2005 [8]: AV Rule 32 The #include pre-processor directive will only be used to include header (*.h) files. HIC++ v4.0 [9]: 16.1.1 Use the preprocessor only for implementing include guards, and including header files with include guards.

Rule M16-0-1 (required, implementation, automated)

#include directives in a file shall only be preceded by other preprocessor directives or comments. See MISRA C++ 2008 [7]

Rule M16-0-2 (required, implementation, automated)

Macros shall only be #define’d or #undef’d in the global namespace. See MISRA C++ 2008 [7]

Rule M16-0-5 (required, implementation, automated)

Arguments to a function-like macro shall not contain tokens that look like pre-processing directives. See MISRA C++ 2008 [7] Note: Function-like macros are anyway not allowed, see A16-0-1. This rule is kept in case A16-0-1 is disabled in a project.

Rule M16-0-6 (required, implementation, automated)

In the definition of a function-like macro, each instance of a parameter shall be enclosed in parentheses, unless it is used as the operand of # or ##. See MISRA C++ 2008 [7] Note: Function-like macros are anyway not allowed, see A16-0-1. This rule is kept in case A16-0-1 is disabled in a project.

Rule M16-0-7 (required, implementation, automated)

Undefined macro identifiers shall not be used in #if or #elif preprocessor directives, except as operands to the defined operator. See MISRA C++ 2008 [7] Note: “#if” and “#elif” are anyway only allowed for conditional file inclusion, see A160-1. This rule is kept in case A16-0-1 is disabled in a project.

Rule M16-0-8 (required, implementation, automated)

If the # token appears as the first token on a line, then it shall be immediately followed by a pre-processing token. See MISRA C++ 2008 [7]

Rule M16-1-1 (required, implementation, automated)

The defined pre-processor operator shall only be used in one of the two standard forms. See MISRA C++ 2008 [7] Note: “#if defined” is anyway only allowed for conditional file inclusion, see A16-0-1. This rule is kept in case A16-0-1 is disabled in a project.

Rule M16-1-2 (required, implementation, automated)

All #else, #elif and #endif pre-processor directives shall reside in the same file as the #if or #ifdef directive to which they are related. See MISRA C++ 2008 [7] Note: “#if”, “#elif”, “#else” and “#ifded” are anyway only allowed for conditional file inclusion, see A16-0-1. This rule is kept in case A16-0-1 is disabled in a project.

Rule M16-2-3 (required, implementation, automated)

Include guards shall be provided. See MISRA C++ 2008 [7]

Rule A16-2-1 (required, implementation, automated)

The ’, ", /*, //, \ characters shall not occur in a header file name or in #include directive.

Rationale

It is undefined behavior if the ’, ", /*, //, \ characters are used in #include directive, between < and > or “ ” delimiters.

Example

// $Id: A16-2-1.cpp 271687 2017-03-23 08:57:35Z piotr.tanski $

// #include <directory/headerfile.hpp> // Compliant
// #include <headerfile.hpp> // Compliant
// #include "directory/headerfile.hpp" // Compliant
// #include "headerfile.hpp" // Compliant
// #include <directory/*.hpp> // Non-compliant

// #include <header’file.hpp> // Non-compliant
// #include <"headerfile.hpp"> // Non-compliant
// #include <directory\\headerfile.hpp> // Non-compliant

See also

MISRA C++ 2008 [7]: Rule 16-2-4 The ’, ", /* or // characters shall not occur in a header file name. MISRA C++ 2008 [7]: Rule 16-2-5 The \character shall not occur in a header file name.

Rule A16-2-2 (required, implementation, automated)

There shall be no unused include directives.

Rationale

Presence of unused include directives considerably slows down compilation phase, makes the code base larger and introduces unneeded dependencies. Note: In order to determine what an unused include directive is, only the immediate level of includes, and the specifications of external libraries shall be considered. So, for example, if a source file uses the standard library algorithm std::copy, it is required (see also rule A16-2-3) to include the standard library header . It is not a violation of this rule if , possibly through inclusion of other headers, contains declarations of symbols not used in the source file.

Example

// $Id: A16-2-2.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <algorithm> // Non-compliant - nothing from algorithm header file is used

#include <array>
// Non-compliant - nothing from array header file is used
#include
<cstdint>
// Compliant
- std::int32_t, std::uint8_t are used
#include
<iostream>
// Compliant
- cout is used
#include <stdexcept> // Compliant - out_of_range is used
7 #include <vector>
// Compliant - vector is used
void Fn1() noexcept
{
std::int32_t x = 0;
// ...
std::uint8_t y = 0;
// ...
}
void Fn2() noexcept(false)
{
try
{
std::vector<std::int32_t> v;
// ...
std::uint8_t idx = 3;
std::int32_t value = v.at(idx);
}
catch (std::out_of_range& e)
{
std::cout << e.what() << ’\n’;
}
}

See also

HIC++ v4.0 [9]: 16.1.5 Include directly the minimum number of headers required for compilation.

Rule A16-2-3 (required, implementation, non-automated)

An include directive shall be added explicitly for every symbol used in a file.

Rationale

All header files that define types or functions used in a file should be included explicitly. The actual header to include depends on the specification of the library/component used.

Exception

Types defined via forward declarations do not violate this rule.

Example

// $Id: A16-2-3.hpp 319944 2018-05-21 09:00:40Z ilya.burylov $
#ifndef HEADER_HPP

#define HEADER_HPP

#include <array>
#include <cstdint>

class B; // Compliant - type B can be included using forward declaration

class OutOfRangeException
: public std::out_of_range // Non-compliant - <stdexcept> which defines
// out_of_range included
// implicitly through <array>
{
public:
using std::out_of_range::out_of_range;
};

class A
{
public:
// Interface of class A

private:
std::array<std::uint32_t, 10>
mArray; // Compliant - <array> included explicitly
B* mB;

std::int32_t mX; // Compliant - <cstdint> included explicitly
};

#endif

See also

none

Rule M16-3-1 (required, implementation, automated)

There shall be at most one occurrence of the # or ## operators in a single macro definition. See MISRA C++ 2008 [7] Note: Operators # and ## are anyway not allowed, see M16-3-2. This rule is kept in case M16-3-2 is disabled in a project.

Rule M16-3-2 (advisory, implementation, automated)

The # and ## operators should not be used. See MISRA C++ 2008 [7]

Rule A16-6-1 (required, implementation, automated)

#error directive shall not be used.

Rationale

Using the pre-processor #error directive may lead to code that is complicated and not clear for developers. The #error directive can not be applied to templates as it will not be evaluated as a per-instance template deduction. Static assertion, similarly to #error directive, provides a compile-time error checking. However, static_assert behaves correctly in all C++ concepts and makes the code more readable and does not rely on pre-processor directives. Note: “#error” is anyway not allowed, see A16-0-1. This rule is kept in case A16-0-1 is disabled in a project.

Example

// $Id: A16-6-1.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <cstdint>
#include <type_traits>
constexpr std::int32_t value = 0;
#if value > 10
#error "Incorrect value" // Non-compliant
#endif
void F1() noexcept
{
static_assert(value <= 10, "Incorrect value"); // Compliant
// ...
}
template <typename T>
void F2(T& a)
{
static_assert(std::is_copy_constructible<T>::value,
"f2() function requires copying");
// Compliant
// ...
}

See also

none

Rule A16-7-1 (required, implementation, automated)

The #pragma directive shall not be used.

Rationale

The #pragma directive is implementation-defined and causes the implementation to behave in implementation-defined manner.

Example

// $Id: A16-7-1.hpp 270497 2017-03-14 14:58:50Z piotr.tanski $
// #pragma once // Non-compliant - implementation-defined manner
#ifndef A16_7_1_HPP // Compliant - equivalent to #pragma once directive
#define A16_7_1_HPP

// ...

#endif

See also

MISRA C++ 2008 [7]: Rule 16-6-1 All uses of the #pragma directive shall be documented.

Rule A17-0-1 (required, implementation, automated)

Reserved identifiers, macros and functions in the C++ standard library shall not be defined, redefined or undefined.

Rationale

It is generally bad practice to #undef a macro that is defined in the standard library. It is also bad practice to #define a macro name that is a C++ reserved identifier, or C++ keyword or the name of any macro, object or function in the standard library. For example, there are some specific reserved words and function names that are known to give rise to undefined behavior if they are redefined or undefined, including defined, LINE, FILE, DATE, TIME, STDC, errno and assert. Refer to C++ Language Standard for a list of the identifiers that are reserved. Generally, all identifiers that begin with the underscore character are reserved.

Note that this rule applies regardless of which header files, if any, are actually included.

Example

// $Id: A17-0-1.cpp 271389 2017-03-21 14:41:05Z piotr.tanski $
2 #undef __TIME__
// Non-compliant
#define __LINE__ 20 // Non-compliant

See also

MISRA C++ 2008 [7]: Rule 17-0-1 Reserved identifiers, macros and functions in the standard library shall not be defined, redefined or undefined.

Rule M17-0-2 (required, implementation, automated)

The names of standard library macros and objects shall not be reused. See MISRA C++ 2008 [7]

Rule M17-0-3 (required, implementation, automated)

The names of standard library functions shall not be overridden. See MISRA C++ 2008 [7]

Rule A17-0-2 (required, implementation, non-automated)

All project’s code including used libraries (including standard and userdefined libraries) and any third-party user code shall conform to the AUTOSAR C++14 Coding Guidelines.

Rationale

Note that library code can be provided as source code or be provided in a compiled form. The rule applies for any form of libraries. As for any rule in this standard, a deviation procedure can be performed for this rule and the project needs to argue what are the measures ensuring that non-compliant libraries can be used in a project, addressing: interference from the non-compliant code (for example, a library function overwrites the stack or heap of the caller) residual errors in non-compliant code resulting with its wrong outputs, which are subsequently used (for example, a library function delivers wrong return value used by the caller).

Exception

If a function is defined in a library or any third-party user code but it is ensured that the function will not be used (directly or indirectly) in the project, then the function may not conform to the AUTOSAR C++14 Coding Guidelines.


## See also
none

Rule M17-0-5 (required, implementation, automated)

The setjmp macro and the longjmp function shall not be used. See MISRA C++ 2008 [7] See: A6-6-1.

Rule A17-1-1 (required, implementation, non-automated)

Use of the C Standard Library shall be encapsulated and isolated.

Rationale

The C Standard Library leaves the responsibility for handling errors, data races and security concerns up to developers. Therefore, use of the C Standard Library needs to be separated and wrapped with functions that will be fully responsible for all specific checks and error handling.

Example

// $Id: A17-1-1.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <cerrno>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <stdexcept>

void Fn1(const char* filename) // Compliant - C code is isolated; fn1()

// function is a wrapper.

{
FILE* handle = fopen(filename, "rb");

if (handle == NULL)
{
throw std::system_error(errno, std::system_category());
}
// ...
fclose(handle);

}

void Fn2() noexcept
{
try
{
Fn1("filename.txt"); // Compliant - fn1() allows you to use C code like
// C++ code

// ...
}
catch (std::system_error& e)
{
std::cerr << "Error: " << e.code() << " - " << e.what() << ’\n’;
}
}

std::int32_t Fn3(const char* filename) noexcept // Non-compliant - placing C

// functions calls along with C++
// code forces a developer to be
// responsible for C-specific error
// handling, explicit resource
// cleanup, etc.
{
FILE* handle = fopen(filename, "rb");

if (handle == NULL)
{
std::cerr << "An error occured: " << errno << " - " << strerror(errno)
<< ’\n’;
return errno;
}

try
{
// ...
fclose(handle);
}
catch (std::system_error& e)
{
fclose(handle);
}
catch (std::exception& e)
{
fclose(handle);
}

return errno;
}

See also

MISRA C++ 2008 [7]: Rule 19-3-1 The error indicator errno shall not be used.

HIC++ v4.0 [9]: 17.2.1 Wrap use of the C Standard Library. JSF December 2005 [8]: Chapter 4.5.1: Standard Libraries, AV Rule 17 - AV Rule 25.

The corresponding section in the C++14 standard provides a glossary only.

Rule A17-6-1 (required, implementation, automated) Non-standard entities shall not be added to standard namespaces.

Rationale

Adding declarations or definitions to namespace std or its sub-namespaces, or to namespace posix or its sub-namespaces leads to undefined behavior. Declaring an explicit specialization of a member function or member function template of a standard library class or class template leads to undefined behavior. Declaring an explicit or partial specialization of a member class template of a standard library class or class template leads to undefined behavior.

Exception

It is allowed by the language standard to add a specialization to namespace std if the declaration depends on a user-defined type, meets the requirements for the original template and is not explicitly forbidden. It is allowed by the language standard to explicitly instantiate a template defined in the standard library if the declaration depends on a user defined type and meets the requirements for the original template.

Example

// $Id: A17-6-1.cpp 305588 2018-01-29 11:07:35Z michal.szczepankiewicz $
#include <cstdint>
#include <limits>
#include <memory>
#include <type_traits>
#include <utility>

namespace std
{

// Non-compliant - An alias definition is added to namespace std.

// This is a compile error in C++17, since std::byte is already defined.
using byte = std::uint8_t;

// Non-compliant - A function definition added to namespace std.
pair<int, int> operator+(pair<int, int> const& x, pair<int, int> const& y)
{
return pair<int, int>(x.first + y.first, x.second + y.second);
}

} // namespace std

struct MyType
{
int value;
};

namespace std
{

// Non-compliant - std::numeric_limits may not be specialized for
// non-arithmetic types [limits.numeric].
template <>
struct numeric_limits<MyType> : numeric_limits<int>
{
};

// Non-compliant - Structures in <type_traits>, except for std::common_type,
// may not be specialized [meta.type.synop].
template <>
struct is_arithmetic<MyType> : true_type
{
};

// Compliant - std::hash may be specialized for a user type if the
// specialization fulfills the requirements in [unord.hash].
template <>
struct hash<MyType>
{
using result_type = size_t;
// deprecated in C++17
using argument_type = MyType; // deprecated in C++17

size_t operator()(MyType const& x) const noexcept
{
return hash<int>()(x.value);
}
};

} // namespace std

See also

SEI CERT C++ Coding Standard [10]: DCL58-CPP: Do not modify the standard namespaces C++ Core Guidelines [11]: SL.3: Do not add non-standard entities to namespace std ISO/IEC 14882:2014 [3]: 17.6.4.2: [namespace.constraints] ISO/IEC 14882:2014 [3]: 18.3.2.1: [limits.numeric] ISO/IEC 14882:2014 [3]: 20.9.13: [unord.hash] ISO/IEC 14882:2014 [3]: 20.10.2: [meta.type.synop]

The corresponding chapter in the C++ standard defines the fundamental support libraries, including integer types, dynamic memory, start and termination.

Rule A18-0-1 (required, implementation, automated)

The C library facilities shall only be accessed through C++ library headers.

Rationale

C libraries (e.g. <stdio.h>) also have corresponding C++ libraries (e.g. ). This rule requires that the C++ version is used.


## See also
MISRA C++ 2008 [7]: Rule 18-0-1 (Required) The C library shall not be used.
HIC++ v4.0 [9]: 1.3.3 Do not use the C Standard Library .h headers.

Rule A18-0-2 (required, implementation, automated)

The error state of a conversion from string to a numeric value shall be checked.

Rationale

Error conditions of a string-to-number conversion must be detected and properly handled. Such errors can happen when an input string: does not contain a number; contains a number, but it is out of range;

contains additional data after a number. Some functions for string-to-number conversion from the C Standard library have undefined behavior when a string cannot be converted to a number, e.g. atoi(). Since the C++11 Language Standard, new numeric conversion functions are available (see: std::stoi(), std::stol(), std::stoll() [16]). These guarantee defined behavior. Moreover, errors shall be checked also for formatted input stream functions (e.g. istream::operator>>()), by using basic_ios::fail().

Example

// $Id: A18-0-2.cpp 312092 2018-03-16 15:47:01Z jan.babst $
#include <cstdint>
#include <cstdlib>
#include <iostream>
#include <string>

std::int32_t F1(const char* str) noexcept

{
return atoi(str); // Non-compliant - undefined behavior if str can not
// be converted
}
std::int32_t F2(std::string const& str) noexcept(false)
{
return std::stoi(str); // Compliant - throws a std::invalid_argument
// exception if str can not be converted
}

std::uint16_t ReadFromStdin1() // non-compliant
{
std::uint16_t a;
std::cin >> a; // no error detection
return a;
}

std::uint16_t ReadFromStdin2() // compliant
{
std::uint16_t a;

std::cin.clear(); // clear all flags
std::cin >> a;
if (std::cin.fail())
{
throw std::runtime_error{"unable to read an integer"};
}
std::cin.clear(); // clear all flags for subsequent operations
return a;
}

See also

MISRA C++ 2008 [7]: 18-0-2: The library functions atof, atoi and atol from library shall not be used. SEI CERT C++ Coding Standard [10]: ERR34-C: Detect errors when converting a string to a number SEI CERT C++ Coding Standard [10]: ERR62-CPP: Detect errors when converting a string to a number

Rule M18-0-3 (required, implementation, automated)

The library functions abort, exit, getenv and system from library shall not be used. See MISRA C++ 2008 [7]

Rule M18-0-4 (required, implementation, automated)

The time handling functions of library shall not be used. See MISRA C++ 2008 [7] Note: Facilities from shall be used instead.

Rule M18-0-5 (required, implementation, automated)

The unbounded functions of library shall not be used. See MISRA C++ 2008 [7] Note: The intention of this rule is to prohibit the functions from which have a char* or char const* parameter, but no additional size_t parameter placing a bound on the underlying loop. Other functions from taking a char _ or char const_ parameter fall under the restrictions of rule A27-0-4. Use of memchr, memcmp, memset, memcpy, and memmove is still allowed by this rule, but limited by rule A120-2.


## See also
Rule A12-0-2 in section 6.12.0
Rule A27-0-4 in section 6.27.1

Rule A18-0-3 (required, implementation, automated)

The library (locale.h) and the setlocale function shall not be used.

Rationale

A call to the setlocale function introduces a data race with other calls to setlocale function.

It may also introduce a data race with calls to functions that are affected by the current locale settings: fprintf, isprint, iswdigit, localeconv, tolower, fscanf, ispunct, iswgraph, mblen, toupper, isalnum, isspace, iswlower, mbstowcs, towlower, isalpha, isupper, iswprint, mbtowc, towupper, isblank, iswalnum, iswpunct, setlocale, wcscoll, iscntrl, iswalpha, iswspace, strcoll, wcstod, isdigit, iswblank, iswupper, strerror, wcstombs, isgraph, iswcntrl, iswxdigit, strtod, wcsxfrm, islower, iswctype, isxdigit, strxfrm, wctomb.


## See also
JSF December 2005 [8]: AV Rule 19 <locale.h> and the setlocale function shall
not be used.

Rule A18-1-1 (required, implementation, automated)

C-style arrays shall not be used.

Rationale

A C-style array is implicitly convertible to a raw pointer and easily loses information about its size. This construct is unsafe, unmaintainable, and a source of potential errors. For fixed-size, stack-allocated arrays, std::array is supposed to be used instead. This type is designed to work with standard library algorithms.

Exception

It is allowed to declare a static constexpr data member of a C-style array type.

Example

// $Id: A18-1-1.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <algorithm>
#include <array>
#include <cstdint>
void Fn() noexcept
{
const std::uint8_t size = 10;
std::int32_t a1[size];
// Non-compliant
std::array<std::int32_t, size> a2; // Compliant
// ...
std::sort(a1, a1 + size);
std::sort(a2.begin(), a2.end()); // More readable and maintainable way of
// working with STL algorithms
}
class A
{
public:

static constexpr std::uint8_t array[]{0, 1, 2}; // Compliant by exception
};

See also

C++ Core Guidelines [11]: ES.27: Use std::array or stack_array for arrays on the stack. C++ Core Guidelines [11]: SL.con.1: Prefer using STL array or vector instead of a C array. Rule A18-1-2 (required, implementation, automated) The std::vector specialization shall not be used.

Rationale

The std::vector specialization does not work with all STL algorithms as expected. In particular, operator does not return a contiguous sequence of elements as it does for the primary template std::vector. The C++ Language Standard guarantees that distinct elements of an STL container can be safely modified concurrently, except when the container is a std::vector< bool>. Note that std::bitset, std::array<bool, N>, std::deque, or using std::vector with a value type which wraps bool are possible alternatives.

Example

// $Id: A18-1-2.cpp 312108 2018-03-16 17:56:49Z jan.babst $
#include <cstdint>
#include <vector>

class BoolWrapper
{
public:
BoolWrapper() = default;
constexpr BoolWrapper(bool b) : b_(b) {}
constexpr operator bool() const { return b_; }
private:
bool b_{};
13 };

// implicit by design
// implicit by design

void Fn() noexcept
{
std::vector<std::uint8_t> v1;
std::vector<bool> v2;
std::vector<BoolWrapper> v3{true, false, true, false}; // Compliant
}

// Compliant
// Non-compliant

See also

HIC++ v4.0 [9]: 17.1.1: Do not use std::vector.

Rule A18-1-3 (required, implementation, automated)

The std::auto_ptr type shall not be used.

Rationale

The std::auto_ptr type has been deprecated since the C++11 Language Standard and is removed from the C++17 Language Standard. Due to the lack of move semantics in pre C++11 standards, it provides unusual copy semantics and cannot be placed in STL containers. The correct alternative is std::unique_ptr, which shall be used instead.

Example

// $Id: A18-1-3.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <cstdint>
#include <memory>
#include <vector>
void Fn() noexcept
{
std::auto_ptr<std::int32_t> ptr1(new std::int32_t(10)); // Non-compliant
std::unique_ptr<std::int32_t> ptr2 =
std::make_unique<std::int32_t>(10);
// Compliant
std::vector<std::auto_ptr<std::int32_t>> v; // Non-compliant
}

See also

HIC++ v4.0 [9]: 1.3.4: Do not use deprecated STL library features. cppreference.com [16]: std::auto_ptr. A1-1-1 in section 6.1.1

Rule A18-1-4 (required, implementation, automated)

A pointer pointing to an element of an array of objects shall not be passed to a smart pointer of single object type.

Rationale

A dynamically allocated array of objects needs a corresponding deallocation function, e.g. allocation by new[] requires deallocation by delete[], see also rule A18-5-3 in section 6.18.5. Smart pointers of a single object type, e.g. std::unique_ptr and std::shared_ptr, by default have a deleter associated with them which is only capable of deleting a single object. Therefore, it is undefined behavior if a pointer pointing to an element of an array of objects is passed to such a

smart pointer. With the standard library smart pointer templates std::unique_ptr and std::shared_ptr, this is possible when calling the constructor or the reset function. Note that the standard library provides a specialization of the std::unique_ptr template for array types, std::unique_ptr<T[]>, and corresponding overloads for std::make_unique. Usage of these features is conforming to this rule. Note that corresponding features for std::shared_ptr are only available in C++17 (usage of std::shared_ptr<T[]> with C++11 and C++14 will lead to compilation errors). The overloads for std::make_shared will only be available in C++20. Furthermore, note that it is possible to create a smart pointer of single object type with a custom deleter handling an array of objects. This is well behaving as long as this smart pointer is actually managing an array of objects. However, such a use is error-prone, since the smart pointer can be assigned a single object again in the reset function; it may no longer be possible in C++17 (moving a std::unique_ptr<T[]> into a std::shared_ptr is no longer allowed); and it is superseded by better alternatives in C++17 (availability of std:shared_ptr<T[]>). Therefore such usage is considered not compliant to this rule. In many cases, using a container such as std::array or std::vector or a smart pointer to a container, e.g. std::shared_ptr<std::vector>, is a better alternative than a smart pointer to an array of objects.

Example

// $Id: A18-1-4.cpp 313638 2018-03-26 15:34:51Z jan.babst $
#include <memory>
class A
{
};
void F1()
{
// Create a dynamically allocated array of 10 objects of type A.
auto up1 = std::make_unique<A[]>(10); // Compliant

std::unique_ptr<A> up2{up1.release()}; // Non-compliant
}
void F2()
{
auto up1 = std::make_unique<A[]>(10); // Compliant

std::unique_ptr<A> up2;
up2.reset(up1.release()); // Non-compliant
}
void F3()
{
auto up = std::make_unique<A[]>(10); // Compliant

std::shared_ptr<A> sp{up.release()}; // Non-compliant
}

void F4()
{
auto up = std::make_unique<A[]>(10); // Compliant

std::shared_ptr<A> sp;
sp.reset(up.release()); // Non-compliant
}
void F5()
{
auto up = std::make_unique<A[]>(10); // Compliant

// sp will obtain its deleter from up, so the array will be correctly
// deallocated. However, this is no longer allowed in C++17.
std::shared_ptr<A> sp{std::move(up)}; // Non-compliant
sp.reset(new A{});
// leads to undefined behavior
}
void F6()
{
auto up = std::make_unique<A[]>(10); // Compliant

// Well behaving, but error-prone
std::shared_ptr<A> sp{up.release(),
std::default_delete<A[]>{}};
sp.reset(new A{}); // leads to undefined behavior
}

// Non-compliant

See also

HIC++ v4.0 [9]: 17.3.4: Do not create smart pointers of array type. ISO/IEC 14882:2014 [3]: 20.8 Smart pointers: [smartptr] Rule A18-5-3 in section 6.18.5

Rule A18-1-6 (required, implementation, automated)

All std::hash specializations for user-defined types shall have a noexcept function call operator.

Rationale

Some of standard library containers use std::hash indirectly. Function call operator should be defined as noexcept to prevent container simple access from throwing an exception. Note: Consider own hash specializations to use standard library specializations combined with XOR (ˆ) operation as implemented by boost::hash_combine: seed ^= std::hash< decltype (v)>{}(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);

Example

// $Id: A18-1-6.cpp 311792 2018-03-15 04:15:08Z christof.meerwald $

#include <cstdint>
#include <functional>
#include <string>
#include <unordered_map>

class A
{
public:
A(uint32_t x, uint32_t y) noexcept : x(x), y(y) {}

uint32_t GetX() const noexcept { return x; }
uint32_t GetY() const noexcept { return y; }

friend bool operator == (const A &lhs, const A &rhs) noexcept
{ return lhs.x == rhs.x && lhs.y == rhs.y; }
private:
uint32_t x;
uint32_t y;
};

class B
{
public:
B(uint32_t x, uint32_t y) noexcept : x(x), y(y) {}

uint32_t GetX() const noexcept { return x; }
uint32_t GetY() const noexcept { return y; }

friend bool operator == (const B &lhs, const B &rhs) noexcept
{ return lhs.x == rhs.x && lhs.y == rhs.y; }
private:
uint32_t x;
uint32_t y;
};

namespace std
{
// Compliant
template <>
struct hash<A>
{
std::size_t operator()(const A& a) const noexcept
{
auto h1 = std::hash<decltype(a.GetX())>{}(a.GetX());
std::size_t seed { h1 + 0x9e3779b9 };
auto h2 = std::hash<decltype(a.GetY())>{}(a.GetY());
seed ^= h2 + 0x9e3779b9 + (seed << 6) + (seed >> 2);
return seed;
}
};

// Non-compliant: string concatenation can potentially throw
template <>
struct hash<B>
{
std::size_t operator()(const B& b) const
{
std::string s{std::to_string(b.GetX()) + ’,’ + std::to_string(b.GetY())};
return std::hash<std::string>{}(s);
}
};
}

int main()
{
std::unordered_map<A, bool> m1 { { A{5, 7}, true } };

if (m1.count(A{4, 3}) != 0)
{
// ....
}

std::unordered_map<B, bool> m2 { { B{5, 7}, true } };

// Lookup can potentially throw if hash function throws
if (m2.count(B{4, 3}) != 0)
{
// ....
}
}

See also

C++ Core Guidelines [11]: C.89: Make a hash noexcept.

Rule M18-2-1 (required, implementation, automated)

The macro offsetof shall not be used. See MISRA C++ 2008 [7]

The dynamic memory management provides flexible mechanism of allocating and deallocating blocks of memory during run-time phase of the program. The application is allowed to acquire as much memory as it needs in its current state, and return it once the memory is not used.

Moreover, this is a convenient way of extending lifetime of objects outside the functions where the objects were created. In other words, a function can create objects on dynamic memory and then exit and the objects that were created in the dynamic memory are preserved and can be used subsequently by other functions. The dynamic memory management uses the Operating System routines to allocate and deallocate memory, what introduces several issues. Therefore, the AUTOSAR C++14 Coding Guidelines defines specific rules for appropriate usage and implementation of dynamic memory management. Challenges arising due to dynamic memory usage Issue:

Solution:

Memory leaks

RAII design pattern usage is highly recommended for managing resource and memory acquisition and release (A18-5-2). It is prohibited to make calls to new and delete operators explicitly, to force programmers to assign each allocated memory block to manager object which deallocates the memory automatically on leaving its scope. Also, the form of delete operator used for memory deallocation needs to match the form of new operator used for memory allocation (A18-5-3).

Memory fragmentation

Memory allocator used in the project needs to guarantee that no memory fragmentation occurs (A18-5-5).

Invalid memory access

C-style functions malloc/calloc/realloc must not be used in the project, so memory block can not be accessed as it would be of another type. Memory allocator used in the project needs to guarantee that objects do not overlap in the physical storage (A185-5).

Erroneous memory allocations

The application program needs to define the maximum amount of dynamic memory it needs, so running out of memory must not occur during faultless execution. The memory would be preallocated before run-time phase of the program (A18-5-5).

Not deterministic execution time of memory allocation and deallocation

Memory allocator used in the project needs to guarantee that memory allocation and deallocation are executed within defined time constraints that are appropriate for the response time constraints defined for the real-time system and its programs (A18-5-7).

Table 6.2: Challenged of dynamic memory usage

Ownership and smart pointers Memory allocated dynamically requires strict control of objects or functions that are responsible for deallocating it when it is no longer needed. Such lifetime manipulation and maintenance of managing dynamically allocated memory is called Ownership. Ownership has the following features: if it is exclusive, then it is possible to transfer it from one scope to another. if it is shared, then memory deletion is typically responsibility of the last owner that releases that ownership. if it is temporary, then a non-owning/weak reference has to be converted to shared ownership before accessing the object. Since C++11, management of Ownership is done by smart pointer types. Smart pointers are allocated on stack, which guarantees destructor execution and possible object deallocation (if that is the last or sole owner) at the end of the scope. Pointerlike behavior is done by overloading operator-> and operator* methods. The following standard smart pointer classes are available since C++11: std::unique_ptr wraps a pointer to an object in an exclusive way. Such std:: unique_ptr

object guarantees that only one pointer to the underlying object exists at a time, as std::unique_ptr is not copyable. It is movable and such an operation represents ownership transfer. When the std::unique_ptr instance is goes out of scope, the underlying pointer is deleted and memory is deallocated. std::shared_ptr wraps a pointer to an object in a shared way. Multiple std:: shared_ptr

are capable to point at the same object, as std::shared_ptr is copyable and it contains a reference counting mechanism. When the last std::shared_ptr instance goes out of scope (and the reference counter drops to 0), the underlying pointer is deleted and memory is deallocated. std::weak_ptr wraps a pointer to an object, but it has to be converted to a std ::shared_ptr in order to access the referenced object. The main purpose of the std::weak_ptr is to break potential circular references among multiple std ::shared_ptr

objects, which would prevent reference counting from dropping to 0 and removing the underlying pointer. If only std::weak_ptr objects exist at a time, then conversion to std::shared_ptr will return an empty std::shared_ptr.

The main purpose of smart pointers is prevent from possible memory leaks to provide limited garbage-collection feature: with almost no overhead over raw pointers for std::unique_ptr, unless userspecified deleter is used. with possibility of sharing ownership among multiple std::shared_ptr objects. However, this solution bases purely on the reference-counting and smart pointers destructors calling and it does not involve independent process that periodically cleans up memory that is no longer referenced.

Usage of smart pointers makes Ownership matters unambiguous and selfdocumenting. It also facilitates memory management issues and eliminates multiple error types that can be made by developers. There are also other types of memory managing objects that follow RAII design pattern, e.g. std::string and std::vector.

Rule A18-5-1 (required, implementation, automated)

Functions malloc, calloc, realloc and free shall not be used.

Rationale

C-style allocation/deallocation using malloc/calloc/realloc/free functions is not type safe and does not invoke class’s constructors and destructors. Note that invoking free function on a pointer allocated with new, as well as invoking delete on a pointer allocated with malloc/realloc/calloc function, result in undefined behavior. Also, note that realloc function should only be used on memory allocated via malloc or calloc functions.

Exception

This rule does not apply to dynamic memory allocation/deallocation performed in user-defined overloads of new and delete operators or malloc and free functions custom implementations.

Example

// $Id: A18-5-1.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <cstdint>
#include <cstdlib>
void F1() noexcept(false)
{
// Non-compliant
std::int32_t* p1 = static_cast<std::int32_t*>(malloc(sizeof(std::int32_t)));

*p1 = 0;

// Compliant
std::int32_t* p2 = new std::int32_t(0);

// Compliant
delete p2;

// Non-compliant
free(p1);

// Non-compliant
std::int32_t* array1 =
static_cast<std::int32_t*>(calloc(10, sizeof(std::int32_t)));

// Non-compliant
std::int32_t* array2 =
static_cast<std::int32_t*>(realloc(array1, 10 * sizeof(std::int32_t)));

// Compliant
std::int32_t* array3 = new std::int32_t[10];

// Compliant
delete[] array3;

// Non-compliant
free(array2);

// Non-compliant
free(array1);
}
void F2() noexcept(false)
{
// Non-compliant
std::int32_t* p1 = static_cast<std::int32_t*>(malloc(sizeof(std::int32_t)));

// Non-compliant - undefined behavior
delete p1;

std::int32_t* p2 = new std::int32_t(0); // Compliant

free(p2); // Non-compliant - undefined behavior
}
void operator delete(void* ptr) noexcept

{
std::free(ptr); // Compliant by exception
}

See also

HIC++ v4.0 [9]: 5.3.2 Allocate memory using new and release it using delete. C++ Core Guidelines [11]: R.10: Avoid malloc() and free().

Rule A18-5-2 (required, implementation, partially automated)

Non-placement new or delete expressions shall not be used.

Rationale

If a resource returned by a non-placement new expression is assigned to a raw pointer, then a developer’s mistake, an exception or a return may lead to memory leak.

It is highly recommended to follow RAII design pattern or use manager objects that manage the lifetime of variables with dynamic storage duration, e.g.: std::unique_ptr along with std::make_unique

std::shared_ptr along with std::make_shared std::string std::vector Note: Functions that do not extend lifetime shall not take parameters as smart pointers, see A8-4-11.

Exception

If the result of explicit resource allocation using a new expression is immediately passed to a manager object or an RAII class which does not provide a safe alternative for memory allocation, then it is not a violation of this rule. This rule does not apply to dynamic memory allocation/deallocation performed in user-defined RAII classes and managers. Placement new expression is allowed, see A18-5-10.

Example

// $Id: A18-5-2.cpp 316977 2018-04-20 12:37:31Z christof.meerwald $
#include <cstdint>
#include <memory>
#include <vector>
std::int32_t Fn1()
{
std::int32_t errorCode{0};

std::int32_t* ptr =

new std::int32_t{0}; // Non-compliant - new expression
// ...
if (errorCode != 0)
{
throw std::runtime_error{"Error"}; // Memory leak could occur here
}
// ...

if (errorCode != 0)
{
return 1; // Memory leak could occur here
}

// ...
delete ptr; // Non-compilant - delete expression

return errorCode;
}
std::int32_t Fn2()
{
std::int32_t errorCode{0};

std::unique_ptr<std::int32_t> ptr1 = std::make_unique<std::int32_t>(

0); // Compliant - alternative for ’new std::int32_t(0)’

std::unique_ptr<std::int32_t> ptr2(new std::int32_t{
0}); // Non-compliant - unique_ptr provides make_unique
// function which
shall be used instead of explicit
// new expression

std::shared_ptr<std::int32_t> ptr3 =
std::make_shared<std::int32_t>(0); // Compliant

std::vector<std::int32_t> array; // Compliant
// alternative for dynamic array

if (errorCode != 0)
{
throw std::runtime_error{"Error"}; // No memory leaks
}
// ...
if (errorCode != 0)
{
return 1; // No memory leaks
}
// ...
return errorCode; // No memory leaks
}
template <typename T>
class ObjectManager
{
public:
explicit ObjectManager(T* obj) : object{obj} {}

~ObjectManager() { delete object; } // Compliant by exception
// Implementation

private:
T* object;

};
std::int32_t Fn3()
{
std::int32_t errorCode{0};

ObjectManager<std::int32_t> manager{
new std::int32_t{0}}; // Compliant by exception
if (errorCode != 0)
{
throw std::runtime_error{"Error"}; // No memory leak
}
// ...
if (errorCode != 0)
{
return 1; // No memory leak
}

// ...
return errorCode; // No memory leak
}

See also

C++ Core Guidelines [11]: R.11: Avoid calling new and delete explicitly. C++ Core Guidelines [11]: R.12: Immediately give the result of an explicit resource allocation to a manager object. C++ Core Guidelines [11]: ES.60: Avoid new and delete outside resource management functions.

Rule A18-5-3 (required, implementation, automated)

The form of the delete expression shall match the form of the new expression used to allocate the memory.

Rationale

Plain and array forms of new and delete expressions must not be mixed. If an array was allocated using a new expression, then an array delete expression must be used to deallocate it and vice versa.

Example

// $Id: A18-5-3.cpp 316977 2018-04-20 12:37:31Z christof.meerwald $
#include <cstdint>

void Fn1()
{
std::int32_t* array =

new std::int32_t[10]; // new expression used to allocate an
// array object
// ...
delete array; // Non-compliant - array delete expression supposed
// to be used
}
void Fn2()
{
std::int32_t* object = new std::int32_t{0}; // new operator used to

// allocate the
// integer type

memory for an

// ...
delete[] object; // Non-compliant - non-array delete expression supposed
// to be used
}
void Fn3()
{
std::int32_t* object = new std::int32_t{0};

std::int32_t* array = new std::int32_t[10];
// ...
delete[] array; // Compliant
delete object;
// Compliant
}

See also

HIC++ v4.0 [9]: 5.3.3 Ensure that the form of delete matches the form of new used to allocate the memory.

Rule A18-5-4 (required, implementation, automated)

If a project has sized or unsized version of operator “delete” globally defined, then both sized and unsized versions shall be defined.

Rationale

Since C++14 Language Standard it is allowed to overload both sized and unsized versions of the “delete” operator. Sized version provides more efficient way of memory deallocation than the unsized one, especially when the allocator allocates in size categories instead of storing the size nearby the object.

Example

//% $Id: A18-5-4.cpp 289415 2017-10-04 09:10:20Z piotr.serwa $
#include <cstdlib>
void operator delete(
void* ptr) noexcept // Compliant - sized version is defined

{
std::free(ptr);
}
void operator delete(
void* ptr,

std::size_t size) noexcept // Compliant - unsized version is defined
{
std::free(ptr);
}

See also

none

Rule A18-5-5 (required, toolchain, partially automated)

Memory management functions shall ensure the following: (a) deterministic behavior resulting with the existence of worst-case execution time, (b) avoiding memory fragmentation, (c) avoid running out of memory, (d)

avoiding mismatched allocations or deallocations, (e) no dependence on non-deterministic calls to kernel.

Rationale

Memory management errors occur commonly and they can affect application stability and correctness. The main problems of dynamic memory management are as following: Non deterministic worst-case execution time of allocation and deallocation Invalid memory access Mismatched allocations and deallocations Memory fragmentation Running out of memory Custom memory management functions (custom allocators) need to address all of this problems for the project and all libraries used in the project. To ensure the worst-case execution time, the memory management functions need to be executed without context switch and without syscalls. To prevent running out of memory, an executable is supposed to define its maximal memory needs, which are pre-allocated for this executable during its startup. Memory management functions include operators new and delete, as well as lowlevel functions malloc and free. Nevertheless code written in C++ language uses new and delete operators, and direct use of malloc and free operations do not occur, some libraries, e.g. exception handling mechanism routines of libgcc uses malloc and free functions directly and omits new and delete operators usage. Custom memory management functionality needs to provide custom implementation of C++ new and delete operators, as well as implementation of malloc and free operations to hide incorrect dynamic memory allocation/deallocation in linked libraries. Note: If custom memory management requires to use custom std::new_handler, its implementation shall perform one of the following: make more storage available for allocation and then return throw an exception of type bad_alloc or a class derived from bad_alloc terminate execution of the program without returning to the caller

Example

//% $Id: A18-5-5.cpp 289815 2017-10-06 11:19:11Z michal.szczepankiewicz $

#define __GNU_SOURCE
#include <dlfcn.h>
#include <cstddef>

void* MallocBad(size_t size) // Non-compliant, malloc from libc does not
// guarantee deterministic execution time
{
void* (*libcMalloc)(size_t) = (void* (*)(size_t))dlsym(RTLD_NEXT, "malloc");

return libcMalloc(size);
}

void FreeBad(void* ptr) // Non-compliant, malloc from libc does not guarantee

// deterministic execution time

{
void (*libcFree)(void*) = (void (*)(void*))dlsym(RTLD_NEXT, "free");

libcFree(ptr);
}

void* MallocGood(size_t size) // Compliant - custom malloc implementation that

// will guarantee deterministic execution time
{
// Custom implementation that provides deterministic worst-case execution
// time
}

void FreeGood(void* ptr) // Compliant - custom malloc implementation that will

// guarantee deterministic execution time
{
// Custom implementation that provides deterministic worst-case execution
// time
}

See also

none Rule A18-5-6 (required, verification / toolchain, non-automated)An analysis shall be performed to analyze the failure modes of dynamic memory management. In particular, the following failure modes shall be analyzed: (a) non-deterministic behavior resulting with nonexistence of worst-case execution time, (b) memory fragmentation, (c) running out of memory, (d) mismatched allocations and deallocations, (e) dependence on non-deterministic calls to kernel.

Rationale

The worst-case execution time and behavior of memory management functions are specific to each implementation. In order to use dynamic memory in the project, an analysis needs to be done to determine possible errors and worst-case execution time of allocation and deallocation functions. Note that standard C++ implementation violates some of this requirements. However, listed problems can be addressed by implementing or using a custom memory allocator.


## See also
none

Rule A18-5-7 (required, implementation, non-automated)

If non-realtime implementation of dynamic memory management functions is used in the project, then memory shall only be allocated and deallocated during non-realtime program phases.

Rationale

If worst-case execution time of memory management functions can not be determined, then dynamic memory usage is prohibited during realtime program phase, but it can be used e.g. during initialization or non-realtime state transitions. See: Real-time.

Example

//% $Id: A18-5-7.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <cstdint>
#include <memory>
#include <vector>
std::int8_t AppMainLoop() noexcept
{
std::int8_t retCode = 0;
std::int32_t* arr[10];

while (true)
{
for (std::int8_t i = 0; i < 10; ++i)
{
arr[i] = new std::int32_t{
i}; // Non-compliant - allocation in a phase that
// requires real-time
}
// Implementation
for (auto& i : arr)
{
delete i; // Non-compliant - deallocation in a phase that requires
// real-time
}
}
return retCode;
}
static std::int32_t* object =

new std::int32_t{0}; // Compliant- allocating in start-up phase

int main(int, char**)

{
std::unique_ptr<std::int32_t> ptr =
std::make_unique<std::int32_t>(0); // Compliant

std::vector<std::int32_t> vec;
vec.reserve(10);

// Compliant
// Compliant

std::int8_t code = AppMainLoop();
return code;
}

See also

none

Rule A18-5-8 (required, implementation, partially automated)

Objects that do not outlive a function shall have automatic storage duration.

Rationale

Creating objects with automatic storage duration implies that there is no additional allocation and deallocation cost, which would occur when using dynamic storage. Note: This rule applies only to objects created in a function scope, it does not forbid the object to internally allocate additional memory on heap.

Exception

Objects causing high memory utilization may be allocated on heap using memory managing objects.

Example

//% $Id: A18-5-8.cpp 311792 2018-03-15 04:15:08Z christof.meerwald $
#include <cstdint>
#include <memory>
#include <vector>

class StackBitmap
{
public:
constexpr static size_t maxSize = 65535;
using BitmapRawType = std::array<uint8_t, maxSize>;
StackBitmap(const std::string& path, uint32_t bitmapSize)
{
// read bitmapSize bytes from the file path
}

const BitmapRawType& GetBitmap() const noexcept { return bmp; }

private:
BitmapRawType bmp;
};

void AddWidgetToLayout(int32_t row, int32_t col)
{
auto idx = std::make_pair(row, col); // Compliant
auto spIdx = std::make_shared<std::pair<int32_t, int32_t>>(
row, col); // Non-compliant
// addWidget to index idx
}

uint8_t CalcAverageBitmapColor(const std::string& path, uint32_t bitmapSize)
{
std::vector<uint8_t> bmp1(bitmapSize); // Compliant
// read bitmap from path
StackBitmap bmp2(path, bitmapSize); // Non-compliant
bmp2.GetBitmap();
}

int main(int, char**)

{
AddWidgetToLayout(5, 8);
CalcAverageBitmapColor("path/to/bitmap.bmp", 32000);
}

See also

C++ Core Guidelines [11]: R.5: Prefer scoped objects, don’t heap-allocate unnecessarily.

Rule A18-5-9 (required, implementation, automated)

Custom implementations of dynamic memory allocation and deallocation functions shall meet the semantic requirements specified in the corresponding “Required behaviour” clause from the C++ Standard.

Rationale

It is possible to provide custom implementations of global dynamic memory allocation/deallocation functions. Requirements for custom implementations for each function declaration are specified in the C++ Standard in the section “Required behaviour”. If the provided function do not implement the required semantics, it can lead to undefined behaviour.

Example

//% $Id: A18-5-9.cpp 305629 2018-01-29 13:29:25Z piotr.serwa $
#include <new>

void* operator new(std::size_t count, const std::nothrow_t& tag)

{
extern void* custom_alloc(std::size_t); // Implemented elsewhere; may return

nullptr
if (void *ret = custom_alloc(count))

{

return ret;
}
throw std::bad_alloc(); //non-compliant, this version of new method shall not throw exceptions

}

See also

SEI CERT C++ Coding Standard [10]: MEM55-CPP: Honor replacement dynamic storage management requirements

Rule A18-5-10 (required, implementation, automated)

Placement new shall be used only with properly aligned pointers to sufficient storage capacity.

Rationale

Placement new can be useful for cases in which allocation is required separately from type initialization, e.g. memory allocators, generic containers. Correct usage of placement new requires passing a pointer that: is suitably aligned provides sufficient storage memory Violating above constrains will result in an object constructed at a misaligned location or memory initialization outside of the allocated bounds, which leads to undefined behaviour. An initial memory pointer used for placement new shall not be used after the call.

Example

//% $Id: A18-5-10.cpp 305629 2018-01-29 13:29:25Z piotr.serwa $

#include <new>
#include <cstdint>

void Foo()
{
uint8_t c;
uint64_t* ptr = ::new (&c) uint64_t;

//non-compliant, insufficient storage
}

void Bar()
{
uint8_t c; // Used elsewhere in the function
uint8_t buf[sizeof(uint64_t)];
uint64_t* ptr = ::new (buf) uint64_t;

//non-compliant, storage not properly aligned
}

See also

SEI CERT C++ Coding Standard [10]: MEM54-CPP: Provide placement new with properly aligned pointers to sufficient storage capacity Rule A18-5-11 (required, implementation, automated) “operator new” and “operator delete” shall be defined together.

Rationale

Providing a custom allocation function (operator new) for a class or program implies the use of a custom memory management scheme different to the default one. It is therefore unlikely that memory allocated using a custom allocation function can be deallocated by the default deallocation function (operator delete).

Example

//% $Id: A18-5-11.cpp 316977 2018-04-20 12:37:31Z christof.meerwald $
#include <cstdlib>

class A {
public:
static void * operator new(std::size_t s); // Compliant: operator new

static void operator delete(void *ptr);

// defined together with
// operator delete

};

class B {
public:

static void * operator new(std::size_t s);

// Non-compliant: operator

static void * operator new [](std::size_t s); // new defined without

// corresponding operator
// delete

};

See also

HIC++ v4.0 [9]: 12.3.1: Correctly declare overloads for operator new and delete

Rule M18-7-1 (required, implementation, automated)

The signal handling facilities of shall not be used.

See MISRA C++ 2008 [7]

Rule A18-9-1 (required, implementation, automated)

The std::bind shall not be used.

Rationale

Using the std::bind function makes the function call less readable and may lead to the developer confusing one function parameter with another. Also, compilers are less likely to inline the functions that are created using std::bind. It is recommended to use lambda expressions instead.

Example

// $Id: A18-9-1.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <cstdint>
#include <functional>
class A
{
// Implementation
};
void Fn(A const& a, double y) noexcept
{
// Implementation
}
void F1() noexcept
{
double y = 0.0;
auto function = std::bind(&Fn, std::placeholders::_1, y); // Non-compliant
// ...
A const a{};
function(a);
}
void F2() noexcept
{
auto lambda = [](A const& a) -> void {
double y = 0.0;
Fn(a, y);
}; // Compliant
// ...
A const a{};
lambda(a);
}

See also

Effective Modern C++ [13]: Item 34: Prefer lambdas to std::bind

Rule A18-9-2 (required, implementation, automated)

Forwarding values to other functions shall be done via: (1) std::move if the value is an rvalue reference, (2) std::forward if the value is forwarding reference.

Rationale

The std::move function unconditionally casts an rvalue reference to rvalue, while the std::forward function does the same if and only if the argument was initialized with an rvalue. Both functions should be used as follows: std::move should be used for forwarding rvalue references to other functions, as rvalue reference always bounds to rvalue std::forward should be used for forwarding forwarding references to other functions, as forwarding reference might be bound to lvalue or rvalue Note that parameter of type “auto&&” is also considered as a forwarding reference for the purpose of this rule.

Example

// $Id: A18-9-2.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <cstdint>
#include <string>
#include <utility>
class A
{
public:
explicit A(std::string&& s)
: str(std::move(s))
// Compliant - forwarding rvalue reference
{
}

private:
std::string str;
};
class B
{
};
void Fn1(const B& lval)
{
}
void Fn1(B&& rval)
{
}
template <typename T>
void Fn2(T&& param)
{
Fn1(std::forward<T>(param)); // Compliant - forwarding forwarding reference
}
template <typename T>

void Fn3(T&& param)
{
Fn1(std::move(param)); // Non-compliant - forwarding forwarding reference
// via std::move
}
void Fn4() noexcept
{
B b1;
B& b2 = b1;
Fn2(b2);
// fn1(const B&) is called
Fn2(std::move(b1)); // fn1(B&&) is called
Fn3(b2);
// fn1(B&&) is called
Fn3(std::move(b1)); // fn1(B&&) is called
}

See also

HIC++ v4.0 [9]:17.3.2 Use std::forward to forward universal references Effective Modern C++ [13]: Item 25. Use std::move on rvalue references, std::forward on universal references.

Rule A18-9-3 (required, implementation, automated)

The std::move shall not be used on objects declared const or const&.

Rationale

If an object is declared const or const&, then it will actually never be moved using the std::move.

Example

// $Id: A18-9-3.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <utility>
class A
{
// Implementation
};
void F1()
{
const A a1{};
A a2 = a1;
// Compliant - copy constructor is called
A a3 = std::move(a1); // Non-compliant - copy constructor is called
// implicitly instead of move constructor
}

See also

HIC++ v4.0 [9]: 17.3.1 Do not use std::move on objects declared with const or const& type.

Rule A18-9-4 (required, implementation, automated)

An argument to std::forward shall not be subsequently used.

Rationale

Depending on the value category of parameters used in the call, std::forward may result in a move of the parameter. When the value is an lvalue, modifications to the parameter will affect the argument of the caller. If the value is an rvalue, the value may be in indeterminate state after the call to std::forward.

Example

// $Id: A18-9-4.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <cstdint>
#include <iostream>
#include <utility>
template <typename T1, typename T2>
void F1(T1 const& t1, T2& t2){
// ...
};
template <typename T1, typename T2>
void F2(T1&& t1, T2&& t2)
{
f1(std::forward<T1>(t1), std::forward<T2>(t2));
++t2; // Non-compliant
};

See also

HIC++ v4.0 [9]: 17.3.3 Do not subsequently use the argument to std::forward.

Rule M19-3-1 (required, implementation, automated)

The error indicator errno shall not be used. See MISRA C++ 2008 [7]

Rule A20-8-1 (required, implementation, automated)

An already-owned pointer value shall not be stored in an unrelated smart pointer.

Rationale

Smart pointers (e.g. std::shared_ptr) that allow to manage the same underlying pointer value using multiple smart pointer objects, shall be created in a way that creates a relationship between two smart pointer objects (e.g. via copy assignment). Unrelated smart pointer objects with a pointer value that is owned by another smart pointer object shall not be created.

Example

// $Id: A20-8-1.cpp 305588 2018-01-29 11:07:35Z michal.szczepankiewicz $

#include <memory>

void Foo()
{
uint32_t *i = new uint32_t{5};

std::shared_ptr<uint32_t> p1(i);
std::shared_ptr<uint32_t> p2(i); // non-compliant
}

void Bar()
{
std::shared_ptr<uint32_t> p1 = std::make_shared<uint32_t>(5);
std::shared_ptr<uint32_t> p2(p1); //compliant
}

See also

SEI CERT C++ Coding Standard [10]: MEM56-CPP: Do not store an alreadyowned pointer value in an unrelated smart pointer

Rule A20-8-2 (required, implementation, automated)

A std::unique_ptr shall be used to represent exclusive ownership.

Rationale

std::unique_ptr is a smart pointer that owns and manages another object and removes it

when it goes out of scope. It has almost no overhead over a raw pointer and clearly states developers intentions and ownership status of the object.

Note: Further usage of the instance of std::unique_ptr in another scope requires transferring ownership using move semantics.

Example

// $Id: A20-8-2.cpp 308981 2018-02-26 08:11:52Z michal.szczepankiewicz $

#include <thread>
#include <memory>

struct A
{
A(std::uint8_t xx, std::uint8_t yy) : x(xx), y(yy) {}
std::uint8_t x;
std::uint8_t y;
};

//consumes object obj or just uses it
void Foo(A* obj) { }

void Bar(std::unique_ptr<A> obj) { }

int main(void)
{
A* a = new A(3,5); //non-compliant with A18-5-2

std::unique_ptr<A> spA = std::make_unique<A>(3,5);

//non-compliant, not clear if function assumes
//ownership of the object
std::thread th1{&Foo, a};
std::thread th2{&Foo, a};
//compliant, it is clear that function Bar
//assumes ownership
std::thread th3{&Bar, std::move(spA)};

th1.join();
th2.join();
th3.join();
return 0;
}

See also

JSF December 2005 [8]: AV Rule 112: Function return values should not obscure resource ownership. C++ Core Guidelines [11]: F.26: Use a unique_ptr to transfer ownership where a pointer is needed C++ Core Guidelines [11]: R.20: Use unique_ptr or shared_ptr to represent ownership

Rule A20-8-3 (required, implementation, automated)

A std::shared_ptr shall be used to represent shared ownership.

Rationale

allows to retain shared ownership by keeping multiple std::shared_ptr instances pointing at the same object. The object is removed when the last std ::shared_ptr instance goes out of scope. Although reference counting mechanism included brings some overhead over a raw pointer, it clearly states ownership status of the object and effectively prevents from possible memory leaks. std::shared_ptr

Example

// $Id: A20-8-3.cpp 308507 2018-02-21 13:23:57Z michal.szczepankiewicz $

#include <memory>
#include <cstdint>
#include <thread>

struct A
{
A(std::uint8_t xx, std::uint8_t yy) : x(xx), y(yy) {}
std::uint8_t x;
std::uint8_t y;
};

void Foo(A* obj) { }
void Bar(A* obj) { }

void Foo2(std::shared_ptr<A> obj) { }
void Bar2(std::shared_ptr<A> obj) { }

int main(void)
{
A* a = new A(3,5); //non-compliant with A18-5-2

std::shared_ptr<A> spA = std::make_shared<A>(3,5);

//non-compliant, not clear who is responsible
//for deleting object a
std::thread th1{&Foo, a};
std::thread th2{&Bar, a};

//compliant, object spA gets deleted
//when last shared_ptr gets destructed
std::thread th3{&Foo2, spA};
std::thread th4{&Bar2, spA};

th1.join();
th2.join();
th3.join();
th4.join();

return 0;
}

See also

JSF December 2005 [8]: AV Rule 112: Function return values should not obscure resource ownership. C++ Core Guidelines [11]: F.27: Use a shared_ptr to share ownership C++ Core Guidelines [11]: R.20: Use unique_ptr or shared_ptr to represent ownership

Rule A20-8-4 (required, implementation, automated)

A std::unique_ptr shall be used over std::shared_ptr if ownership sharing is not required.

Rationale

std::unique_ptr is more predictable in terms of its destruction, as it happens at the end of

the scope unless ownership transfer occurred. It also has lower overhead than a std::shared_ptr, as it does not keep internal reference counting.

Example

// $Id: A20-8-4.cpp 308507 2018-02-21 13:23:57Z michal.szczepankiewicz $

#include <memory>
#include <cstdint>
#include <thread>

struct A
{
A(std::uint8_t xx, std::uint8_t yy) : x(xx), y(yy) {}
std::uint8_t x;
std::uint8_t y;
};

void Func()
{
auto spA = std::make_shared<A>(3,5);
//non-compliant, shared_ptr used only locally
//without copying it
}

void Foo(std::unique_ptr<A> obj) { }
void Bar(std::shared_ptr<A> obj) { }

int main(void)
{
std::shared_ptr<A> spA = std::make_shared<A>(3,5);
std::unique_ptr<A> upA = std::make_unique<A>(4,6);

//compliant, object accesses in parallel

std::thread th1{&Bar, spA};
std::thread th2{&Bar, spA};
std::thread th3{&Bar, spA};

//compliant, object accesses only by 1 thread
std::thread th4{&Foo, std::move(upA)};

th1.join();
th2.join();
th3.join();
th4.join();

return 0;
}

See also

C++ Core Guidelines [11]: R.21: Prefer unique_ptr over shared_ptr unless you need to share ownership

Rule A20-8-5 (required, implementation, automated)

std::make_unique shall be used to construct objects owned by std::unique_ptr.

Rationale

Using std::make_unique to create instances of std::unique_ptr provides object allocation without explicit call of new function, see A18-5-2. It also ensures exception safety in complex expressions and prevents from memory leaks caused by unspecifiedevaluation order-expressions.

Exception

It is allowed to use explicit new function call to create an instance of std::unique_ptr, if it requires a custom deleter.

Example

// $Id: A20-8-5.cpp 308507 2018-02-21 13:23:57Z michal.szczepankiewicz $
#include <memory>
#include <cstdint>
#include <functional>

struct A
{
A() { throw std::runtime_error("example"); }
A(std::uint8_t xx, std::uint8_t yy) : x(xx), y(yy) {}
std::uint8_t x;
std::uint8_t y;
};

void Foo(std::unique_ptr<A> a, std::unique_ptr<A> b) { }

int main(void)
{
//compliant
std::unique_ptr<A> upA = std::make_unique<A>(4,6);
//non-compliant
std::unique_ptr<A> upA2 = std::unique_ptr<A>(new A(5,7));

//non-compliant, potential memory leak, as A class constructor throws
Foo(std::unique_ptr<A>(new A()), std::unique_ptr<A>(new A()));
//non-compliant, potential memory leak, as A class constructor throws
Foo(std::make_unique<A>(4,6), std::unique_ptr<A>(new A()));
//compliant, no memory leaks
Foo(std::make_unique<A>(4,6), std::make_unique<A>(4,6));

//compliant by exception
std::unique_ptr<A, std::function<void(A*)>> ptr(new A(4,5), [](A* b) { delete

b; } );

return 0;
}

See also

C++ Core Guidelines [11]: R.23: Use make_unique() to make unique_ptrs C++ Core Guidelines [11]: C.150: Use make_unique() to construct objects owned by unique_ptrs

Rule A20-8-6 (required, implementation, automated)

std::make_shared shall be used to construct objects owned by std::shared_ptr.

Rationale

std::shared_ptr manages two entities: a control block (for meta data such as reference

counter or type-erased deleter) and an allocated object. Using std::make_shared typically performs a single heap allocation (as it is recommended by the Standard) for both control block and allocated object. std::make_shared function also provides object allocation without explicit call of new function, see A18-5-2. It also ensures exception safety and prevents from memory leaks caused by unspecified-evaluation-order expressions.

Exception

It is allowed to use explicit new function call to create an instance of std::shared_ptr, if it requires a custom deleter. It is also allowed to construct objects owned by std:: shared_ptr using std::allocate_shared.

Example

// $Id: A20-8-6.cpp 308507 2018-02-21 13:23:57Z michal.szczepankiewicz $
#include <memory>
#include <cstdint>
#include <functional>

struct A
{
A() { throw std::runtime_error("example"); }
A(std::uint8_t xx, std::uint8_t yy) : x(xx), y(yy) {}
std::uint8_t x;
std::uint8_t y;
};

void Foo(std::shared_ptr<A> a, std::shared_ptr<A> b) { }

int main(void)
{
//compliant
std::shared_ptr<A> upA = std::make_shared<A>(4,6);
//non-compliant
std::shared_ptr<A> upA2 = std::shared_ptr<A>(new A(5,7));

//non-compliant, potential memory leak, as A class constructor throws
Foo(std::shared_ptr<A>(new A()), std::shared_ptr<A>(new A()));
//non-compliant, potential memory leak, as A class constructor throws
Foo(std::make_shared<A>(4,6), std::shared_ptr<A>(new A()));
//compliant, no memory leaks
Foo(std::make_shared<A>(4,6), std::make_shared<A>(4,6));

//compliant by exception
std::shared_ptr<A> ptr(new A(4,5), [](A* b) { delete b; } );

return 0;
}

See also

C++ Core Guidelines [11]: R.22: Use make_shared() to make shared_ptrs. C++ Core Guidelines [11]: C.151: Use make_shared() to construct objects owned by shared_ptrs

Rule A20-8-7 (required, implementation, non-automated)

A std::weak_ptr shall be used to represent temporary shared ownership.

Rationale

A cyclic structure of std::shared_ptr results in reference counting mechanism never dropping to zero, which prevents from pointed object deallocation. Breaking such

cycles is done using std::weak_ptr which must be converted to std::shared_ptr in order to access the referenced object.

Example

// $Id: A20-8-7.cpp 308795 2018-02-23 09:27:03Z michal.szczepankiewicz $

#include <memory>

template <template <typename> class T, typename U>
struct Base
{
T<U> sp;
};

template <typename T>
using Shared = Base<std::shared_ptr, T>;

template <typename T>
using Weak = Base<std::weak_ptr, T>;

struct SBarSFoo;
struct SFooSBar : public Shared<SBarSFoo> {};
struct SBarSFoo : public Shared<SFooSBar> {};

struct A : public Shared<A> {};

struct WBarSFoo;
struct SFooWBar : public Shared<WBarSFoo> {};
struct WBarSFoo : public Weak<SFooWBar> {};

int main()
{
std::shared_ptr<SFooSBar> f = std::make_shared<SFooSBar>();
std::shared_ptr<SBarSFoo> b = std::make_shared<SBarSFoo>();
f->sp = b;
b->sp = f;
//non-compliant, both f and b have ref_count() == 2
//destructors of f and b reduce ref_count() to 1,
//destructors of underlying objects are never called,
//so destructors of shared_ptrs sp are not called
//and memory is leaked

std::shared_ptr<A> a = std::make_shared<A>();
a->sp = a;
//non-compliant, object ’a’ destructor does not call
//underlying memory destructor

std::shared_ptr<SFooWBar> f2 = std::make_shared<SFooWBar>();
std::shared_ptr<WBarSFoo> b2 = std::make_shared<WBarSFoo>();
f2->sp = b2;
b2->sp = f2;

//compliant, b2->sp holds weak_ptr to f2, so f2 destructor
//is able to properly destroy underlying object

return 0;
}

See also

C++ Core Guidelines [11]: R.24: Use std::weak_ptr to break cycles of shared_ptrs

Rule A21-8-1 (required, implementation, automated)

Arguments to character-handling functions shall be representable as an unsigned char.

Rationale

This rule applies to the character handling functions in . They all take an int parameter as input and specify that its value either shall be EOF or otherwise shall be representable as an unsigned char. On platforms where char is signed, it can have negative values that are not representable as an unsigned char, so that passing a char to such a function can result in undefined behavior. Thus, this rule mandates that all character arguments passed to such functions shall be explicitly cast to unsigned char. Note: Of all the functions in , isdigit and isxdigit are the only ones whose behavior does not depend on the currently installed locale. See A18-0-3 in section

Example

// $Id: A21-8-1.cpp 312606 2018-03-21 09:52:14Z jan.babst $
#include <algorithm>
#include <cctype>
#include <string>

void RemoveDigits_Bad(std::string& s)
{
s.erase(std::remove_if(s.begin(),
s.end(),
[](char c)
return
}),

{
std::isdigit(c); // non-compliant

s.cend());

}

void RemoveDigits_Good(std::string& s)
{
s.erase(std::remove_if(s.begin(),
s.end(),
[](char c) {
return std::isdigit(
static_cast<unsigned char>(c)); // compliant
}),
s.cend());
}

See also

SEI CERT C++ Coding Standard [10]: STR37-C: Arguments to characterhandling functions must be representable as an unsigned char. cppreference.com [16]: Standard library header . Rule A18-0-3 in section 6.18.0

Rule A23-0-1 (required, implementation, automated)

An iterator shall not be implicitly converted to const_iterator.

Rationale

The Standard Template Library introduced methods for returning const iterators to containers. Making a call to these methods and immediately assigning the value they return to a const_iterator, removes implicit conversions.

Example

//% $Id: A23-0-1.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <cstdint>
#include <vector>

void Fn1(std::vector<std::int32_t>& v) noexcept
{
for (std::vector<std::int32_t>::const_iterator iter{v.cbegin()},
end{v.cend()};
iter != end;
++iter) // Compliant
{

// ...
}
}

void Fn2(std::vector<std::int32_t>& v) noexcept
{
for (auto iter{v.cbegin()}, end{v.cend()}; iter != end;
++iter) // Compliant
{
// ...
}
}

void Fn3(std::vector<std::int32_t>& v) noexcept
{
for (std::vector<std::int32_t>::const_iterator iter{v.begin()},
end{v.end()};
iter != end;
++iter) // Non-compliant
{
// ...
}
}

See also

HIC++ v4.0 [9]: 17.4.1 Use const container calls when result is immediately converted to a const iterator.

Rule A23-0-2 (required, implementation, automated)

Elements of a container shall only be accessed via valid references, iterators, and pointers.

Rationale

Some operations on standard library containers invalidate references, iterators, and pointers to container elements which were previously stored. The behavior of the standard library containers and their operations with respect to the invalidation of references, iterators, and pointers is well documented, e.g. in [16].

Example

// $Id: A23-0-2.cpp 309868 2018-03-02 10:47:23Z jan.babst $
#include <algorithm>
#include <cstdint>
#include <list>
#include <vector>

void f()

{
std::vector<int32_t> v{0, 1, 2, 3, 4, 5, 6, 7};

auto it = std::find(v.begin(), v.end(), 5); // *it is 5

// These calls may lead to a reallocation of the vector storage
// and thus may invalidate the iterator it.
v.push_back(8);
v.push_back(9);

*it = 42; // Non-compliant
}

void g()
{
std::list<int32_t> l{0, 1, 2, 3, 4, 5, 6, 7};

auto it = std::find(l.begin(), l.end(), 5); // *it is 5

l.remove(7);
l.push_back(9);

*it = 42; // Compliant - previous operations do not invalidate iterators
// l is now {0, 1, 2, 3, 4, 42, 6, 9 }
}

See also

SEI CERT C++ Coding Standard [10]: CTR51-CPP: Use valid references, pointers, and iterators to reference elements of a container. SEI CERT C++ Coding Standard [10]: STR52-CPP: Use valid references, pointers, and iterators to reference elements of a basic_string. cppreference.com [16]: Containers library. Iterator invalidation.

Rule A25-1-1 (required, implementation, automated) Non-static data members or captured values of predicate function objects that are state related to this object’s identity shall not be copied.

Rationale

Generic algorithms available in the C++ Standard Library accept a predicate function object. The ISO/IEC 14882:2014 C++ Language Standard states that it is implementation-defined whether predicate function objects can be copied by the STL algorithms.

To prevent from unexpected results while using predicate function objects, any such object shall either: be passed to an STL algorithm wrapped as a std::reference_wrapper. implement a function call operator that is const and does not modify any data members or captured values that have a mutable specifier.

Example

//% $Id: A25-1-1.cpp 309784 2018-03-01 20:18:29Z michal.szczepankiewicz $

#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
#include <iterator>

class ThirdElemPred : public std::unary_function<int, bool>
{
public:
ThirdElemPred() : timesCalled(0) {}
bool operator()(const int &) { return (++timesCalled) == 3; }
//non-compliant, non-const call operator that
//modifies the predicate object field
private:
size_t timesCalled;
};

class ThirdElemPred2 : public std::unary_function<int, bool>
{
public:
ThirdElemPred2() : timesCalled(0) {}
bool operator()(const int &) const { return (++timesCalled) == 3; }
//non-compliant, const call operator that
//modifies the mutable predicate object field
private:
mutable size_t timesCalled;
};

class ValueFivePred: public std::unary_function<int, bool>
{
public:
bool operator()(const int& v) const { return v == 5; }
//compliant, const call operator that does not
//modify the predicate object state
};

void F1(std::vector<int> v)
{
//non-compliant, predicate object state modified
int timesCalled = 0;
//display values that are NOT to be removed

std::copy(v.begin(), std::remove_if(v.begin(), v.end(), [timesCalled](const int &) mutable { return
(++timesCalled) == 3; }), std::ostream_iterator<std:: vector<int>::value_type>(std::cout, " ") );
std::cout << std::endl;
}

void F2(std::vector<int> v)
{
//non-compliant, predicate object state modified
std::copy(v.begin(), std::remove_if(v.begin(), v.end(), ThirdElemPred()), std
::ostream_iterator<std::vector<int>::value_type>(std::cout, " ") );
std::cout << std::endl;
}

void F22(std::vector<int> v)
{
//non-compliant, predicate object state modified
std::copy(v.begin(), std::remove_if(v.begin(), v.end(), ThirdElemPred2()),
std::ostream_iterator<std::vector<int>::value_type>(std::cout, " ") );
std::cout << std::endl;
}

void F3(std::vector<int> v)
{
//compliant, predicate object that has its state
//modified is passed as a std::reference_wrapper
ThirdElemPred pred;
std::copy(v.begin(), std::remove_if(v.begin(), v.end(), std::ref(pred)), std
::ostream_iterator<std::vector<int>::value_type>(std::cout, " ") );
std::cout << std::endl;
}

int main(void)
{
std::vector<int> v{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};

F1(v);
F2(v);
F22(v);
F3(v);
//output for g++-5.5, correct result only for F3
80 //F1
81 //F2
82 //F22
83 //F3
return 0;
}

See also

SEI CERT C++ Coding Standard [10]: CTR58-CPP: Predicate function objects should not be mutable cppreference.com [16]: C++ concepts: Predicate

Rule A25-4-1 (required, implementation, non-automated)

Ordering predicates used with associative containers and STL sorting and related algorithms shall adhere to a strict weak ordering relation.

Rationale

Ordering predicates that can be passed to associative containers or sorting STL algorithms and related operations must fulfill requirements for a strict weak ordering, e.g.: irreflexivity: FOR ALL x: x < x == false assymetry: FOR ALL x, y: if x < y then !(y < x) transitivity: FOR ALL x, y, z: if x < y && y < z then x < z

Ordering predicates not adhering to these requirements will result in these algorithms not working correctly, which may include infinite loops and other erratic behavior.

Example

//% $Id: A25-4-1.cpp 309738 2018-03-01 15:08:00Z michal.szczepankiewicz $

#include <functional>
#include <iostream>
#include <set>

int main(void)
{
//non-compliant, given predicate does not return false
//for equal values
std::set<int, std::greater_equal<int>> s{2, 5, 8};
auto r = s.equal_range(5);
//returns 0
std::cout << std::distance(r.first, r.second) << std::endl;

//compliant, using default std::less<int>
std::set<int> s2{2, 5, 8};
auto r2 = s2.equal_range(5);
//returns 1
std::cout << std::distance(r2.first, r2.second) << std::endl;

return 0;

}

See also

SEI CERT C++ Coding Standard [10]: CTR57-CPP: Provide a valid ordering predicate cppreference.com [16]: C++ concepts: Compare

Rule A26-5-1 (required, implementation, automated) Pseudorandom numbers shall not be generated using std::rand().

Rationale

Using a pseudo-random sequence of numbers requires that it is generated with good statistical properties. Some implementations of std::rand() function have a comparatively short cycle, as a result the numbers can be predictable. Using functionalities from is recommended instead of using std::rand(). Note: std::random_shuffle should not be used, as it is deprecated since C++14 (see A1-11) and one of the available overloads is often implemented in terms of std::rand.

Example

// $Id: A26-5-1.cpp 311495 2018-03-13 13:02:54Z michal.szczepankiewicz $

#include <cstdlib>
#include <cstdint>
#include <ctime>
#include <iostream>
#include <random>

int main()
{
std::srand(std::time(nullptr));
int r1 = std::rand() % 100; //non-compliant
std::cout << "Random value using std::rand(): " << r1 << std::endl;

std::random_device rd;
std::default_random_engine eng{rd()};
std::uniform_int_distribution<int> ud{0, 100};
int r2 = ud(eng); //compliant
std::cout << "Random value using std::random_device: " << r2 << std::endl;

return 0;
}

See also

SEI CERT C++ Coding Standard [10]: MSC50-CPP: Do not use std::rand() for generating pseudorandom numbers.

Rule A26-5-2 (required, implementation, automated)

Random number engines shall not be default-initialized.

Rationale

Using a pseudo-random number generator gives different results that depend on a used seed value. Initializing random number engines by default initializes pseudorandom generator with a default_seed constant value. However, this can be not obvious for a developer and can lead to unexpected program behaviour (generating the same random sequences among different program executions).

Exception

For consistent testing purposes it can be convenient to seed the random number engine with a fixed value to get a deterministic sequence, but never within production code where real randomness is required, e.g. for security reasons.

Example

// $Id: A26-5-2.cpp 311495 2018-03-13 13:02:54Z michal.szczepankiewicz $

#include <iostream>
#include <random>

int main()
{
std::random_device rd;
std::default_random_engine eng{rd()}; //compliant
std::uniform_int_distribution<int> ud{0, 100};
int r1 = ud(eng);
std::cout << "Random value using std::random_device: " << r1 << std::endl;

std::default_random_engine eng2{}; //non-compliant
std::uniform_int_distribution<int> ud2{0, 100};
int r2 = ud2(eng);
std::cout << "Random value using std::random_device: " << r2 << std::endl;

return 0;
}

See also

SEI CERT C++ Coding Standard [10]: MSC51-CPP: Ensure your random number generator is properly seeded.

Rule M27-0-1 (required, implementation, automated)

The stream input/output library shall not be used. See MISRA C++ 2008 [7]

Rule A27-0-1 (required, implementation, non-automated)

Inputs from independent components shall be validated.

Rationale

An “attacker” who fully or partially controls the content of an application’s buffer can crash the process, view the content of the stack, view memory content, write to random memory locations or execute code with permissions of the process. This rule concerns network inputs, as well as inputs that are received from other processes or other software components over IPC or through component APIs. Note: If more advanced style formatting is required, this can be done using C++ dedicated libraries (e.g. boost::format or libfmt).

Example

// $Id: A27-0-1.cpp 311495 2018-03-13 13:02:54Z michal.szczepankiewicz $
#include <cstring>
#include <cstdint>
#include <cstdio>
void F1(const char* name) // name restricted to 256 or fewer characters

{
static const char format[] = "Name: %s .";
size_t len = strlen(name) + sizeof(format);
char* msg = new char[len];

if (msg == nullptr)
{
// Handle an error
}

std::int32_t ret =
snprintf(msg,
len,
format,
name); // Non-compliant - no additional check for overflows

if (ret < 0)

{
// Handle an error
}
else if (ret >= len)
{
// Handle truncated output
}

fprintf(stderr, msg);
delete[] msg;
}
void F2(const char* name)

{
static const char format[] = "Name: %s .";
fprintf(stderr, format, name); // Compliant - untrusted input passed as one
// of the variadic arguments, not as part of
// vulnerable format string
}
void F3(const std::string& name)
{
//compliant, untrusted input not passed
//as a part of vulnerable format string
std::cerr << "Name: " << name;
}

See also

SEI CERT C++ [10]: FIO30-C. Exclude user input from format strings.

Rule A27-0-4 (required, implementation, automated)

C-style strings shall not be used.

Rationale

It is required that an underlying buffer for a C-style string needs to be of sufficient size to hold character data and a null terminator. In addition, a C-style string implies all other disadvantages of built-in arrays (see A18-1-1 in section 6.18.1). Using std:: string provides correct memory allocation, copying, gradual expansion and iteration. It is self-explanatory in terms of ownership and offers more readable interface.

Example

// $Id: A27-0-4.cpp 311495 2018-03-13 13:02:54Z michal.szczepankiewicz $
#include <iostream>
#include <string>
#include <list>

void F1()
{
std::string string1;

std::string string2;
std::cin >> string1 >> string2; // Compliant - no buffer overflows
}

std::list<std::string> F2(const std::string& terminator)
{
std::list<std::string> ret;
//read a single word until it is different from the given terminator sequence
for (std::string s; std::cin >> s && s != terminator; )
{
ret.push_back(s);
}
return ret;
}

See also

C++ Core Guidelines [11]: SL.str.1: Use std::string to own character sequences.

Rule A27-0-2 (advisory, implementation, automated)

A C-style string shall guarantee sufficient space for data and the null terminator.

Rationale

To prevent buffer overflows, it needs to be ensured that the destination is of sufficient size to hold the character data to be copied and the null terminator. Note that C-style string requires additional space for null character to indicate the end of the string, while the C++ std::basic_string does that implicitly. Note: This rule is deliberately redundant, in case the rule A27-0-4 is disabled in a project.

Example

// $Id: A27-0-2.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <iostream>
#include <string>
void F1() noexcept
{
char buffer[10];
std::cin >> buffer; // Non-compliant - this could lead to a buffer overflow
}
void F2() noexcept
{
std::string string1;
std::string string2;
std::cin >> string1 >> string2; // Compliant - no buffer overflows
}
void F3(std::istream& in) noexcept

{
char buffer[32];

try
{
in.read(buffer, sizeof(buffer));
}

catch (std::ios_base::failure&)
{
// Handle an error
}

std::string str(buffer); // Non-compliant - if ’buffer’ is not null
// terminated, then constructing std::string leads
// to undefined behavior.
}
void F4(std::istream& in) noexcept
{
char buffer[32];

try
{
in.read(buffer, sizeof(buffer));
}

catch (std::ios_base::failure&)
{
// Handle an error
}

std::string str(buffer, in.gcount()); // Compliant
}

See also

SEI CERT C++ [10]: STR50-CPP. Guarantee that storage for strings has sufficient space for character data and the null terminator.

Rule A27-0-3 (required, implementation, automated)

Alternate input and output operations on a file stream shall not be used without an intervening flush or positioning call.

Rationale

There are following restrictions on reading and writing operations called for an object of class basic_filebuf<charT, traits>: output shall not be directly followed by input without an intervening call to the fflush function or to a file positioning function (fseek, fsetpos, or rewind).

input shall not be directly followed by output without an intervening call to a file positioning function, unless the input operation encounters end-of-file. It is recommended to use a file stream either for output ( std::ofstream) or input(std:: ifstream) and not for both in the same context. This avoids the mentioned problem altogether.

Example

// $Id: A27-0-3.cpp 311495 2018-03-13 13:02:54Z michal.szczepankiewicz $

#include <fstream>
#include <string>

int main(void)
{
std::fstream f("testfile");

f << "Output";
std::string str1;
f >> str1; // non-compliant

f << "More output";
std::string str2;
f.seekg(0, std::ios::beg);
f >> str2; //compliant

return 0;
}

See also

SEI CERT C++ Coding Standard [10]: FIO39-C: Do not alternately input and output from a stream without an intervening flush or positioning call SEI CERT C++ Coding Standard [10]: FIO50-CPP: Do not alternately input and output from a file stream without an intervening positioning call