Main Content

AUTOSAR C++14 Rule A12-7-1

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

Since R2021b

Description

Rule Definition

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

Compilers implicitly define special member functions if these functions are declared as =default or left undefined. These implicitly defined functions are consistent, error-free, and do not require maintenance. If the implicitly defined special member functions are sufficient, then replacing them with user-defined functions makes the code error-prone and harder to maintain. Unless a class manages resources like a raw pointer or a POSIX file descriptor, the implicit definition of the special member functions might be sufficient. Avoid defining the special member functions when the implicit definitions are sufficient.

Default construction of const objects might cause a compilation failure if the nonstatic data members are not initialized during definition. The best practice is to initialize nonstatic data members in the class definition. Alternatively, initialize the const instance by using an empty initializer list. These practices enable the default constructor to correctly construct const instances of a class.

Polyspace Implementation

Polyspace® raises the checker if the user-defined special member functions of your class are the same as the implicitly defined special member functions. The implicit special member functions typically have these properties:

  • The implicit default constructor have an empty body, an empty parameter list, and an empty initializer list.

  • The implicit destructors have an empty body.

  • The implicit copy/move constructor and assignment operators copy/move the base classes and nonstatic data members by using an initializer list. These functions does not perform any deep copy and does not move the data associated with a raw pointer.

For details about how implicitly defined special member function behave, see:

Troubleshooting

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

Examples

expand all

#include <cstdint>
#include <utility>
class A
{
public:
	A() : x(0), y(0) {}                                   // Compliant
	A(std::int32_t first, std::int32_t second)            // Compliant
	: x(first), y(second) {}       
	A(const A& oth) : x(oth.x),y(oth.y){}                 // Noncompliant
	A(A&& oth): x(std::move(oth.x)),y(std::move(oth.y)){} // Noncompliant
	~A(){}                                                // Noncompliant


private:
	std::int32_t x;
	std::int32_t y;
};
class B
{
public:
	B() {}  // Noncompliant 
	B(std::int32_t first, std::int32_t second)// Compliant 
	: x(first), y(second)
	{} 
	B(const B&) = default; // Compliant 
	B(B&&) = default;     // Compliant
	~B() = default;       // Compliant 

private:
	std::int32_t x;
	std::int32_t y;
};
class D
{
public:
	D() : ptr(nullptr) {}  // Compliant - Managing a raw pointer
	D(B* p) : ptr(p) {}    // Compliant - Managing a raw pointer
	D(const D&) = default; // Requires user defined copy constructor
	D(D&&) = default;      // Requires user defined move constructor
	~D() = default;        // Requires user defined destructor

private:
	B* ptr;
};
class E      // Compliant 
{
};

In this example, the classes A, B, and D are defined.

  • For the class A:

    • The user defined default constructor has a nonempty initializer list. Because this definition is different than an implicit default constructor, Polyspace does not report a violation.

    • Because this rule does not apply to nondefault constructors, Polyspace does not report a violation.

    • Because the user-defined copy and move constructors of A do not manage any resources and they can be defined as =default or left undefined, Polyspace reports violations on these functions.

  • For the class B:

    • The default constructor of B is user-defined even though it does not manage any resources. Because this user-defined constructor can be defined as =default or left undefined, Polyspace reports a violation on it.

    • Because the other constructors of B are defined as =default, they are compliant..

  • The class D contains a raw pointer to the class B. For the class D:

    • Because the user-defined constructor explicitly initializes the raw pointer ptr to nullptr, it is different than an implicit constructor. Polyspace does not report a violation.

    • Because the other special member functions are declared as =default, these functions do not violate this rule.

    When managing resources such as a raw pointer, the implicitly defined special member functions are typically incorrect. For instance, the implicit copy constructor of D performs a shallow copy of ptr, without duplicating the underlying resources. When managing raw pointers, the best practice is to define all the special member functions appropriately to avoid unexpected behavior.

class B_NC{
	public:
	//B_NC()=default;// Compile fail
	B_NC(){}         //Noncompliant
	int x;
};
class B_C{
	public:
	B_C() = default;//Compliant
	int x = 0;
};
const B_NC a;
const B_C b;

In this example, classes B_NC and B_C are defined and const instances of these classes are constructed. According to the C++ standard, a const object can be constructed by the implicit default constructor only if all the members of the object is const-default-constructible. The variable B_NC::x cannot be const-default-constructed. If you declare the constructor as =default, constructing a const instance of B_NC results in a compilation failure. To resolve the compilation failure, you might want to provide a user-defined constructor that is identical to the implicit constructor, such as the constructor B_NC::B_NC() in the preceding code. Though this code compiles, B_NC::B_NC() is noncompliant with this rule.

To resolve the compilation failure without violating this rule, initialize the nonstatic data members of the class in its definition, as shown in the definition of B_C. Because B_C::x can be const-default-constructed, a const instance of B_C can be constructed by the implicit default constructor. After initializing the nonstatic data members, set the constructor to =default.

Check Information

Group: Special member functions
Category: Required, Automated

Version History

Introduced in R2021b

expand all