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.