C++ Rule of 5 – To Use or Not?

cclean coderule-of-three

The rule of 3 (the rule of 5 in the new c++ standard) states :

If you need to explicitly declare either the destructor, copy constructor or copy assignment operator yourself, you probably need to explicitly declare all three of them.

But, on the other hand, the Martin's "Clean Code" advises to remove all empty constructors and destructors (page 293, G12:Clutter) :

Of what use is a default constructor with no implementation? All it serves to do is clutter up the code with meaningless artifacts.

So, how to handle these two opposite opinions? Should empty constructors/destructors really be implemented?


Next example demonstrates exactly what I mean :

#include <iostream>
#include <memory>

struct A
{
    A( const int value ) : v( new int( value ) ) {}
    ~A(){}
    A( const A & other ) : v( new int( *other.v ) ) {}
    A& operator=( const A & other )
    {
        v.reset( new int( *other.v ) );
        return *this;
    }

    std::auto_ptr< int > v;
};
int main()
{
    const A a( 55 );
    std::cout<< "a value = " << *a.v << std::endl;
    A b(a);
    std::cout<< "b value = " << *b.v << std::endl;
    const A c(11);
    std::cout<< "c value = " << *c.v << std::endl;
    b = c;
    std::cout<< "b new value = " << *b.v << std::endl;
}

Compiles fine using g++ 4.6.1 with :

g++ -std=c++0x -Wall -Wextra -pedantic example.cpp

The destructor for struct A is empty, and not really needed. So, should it be there, or should it be removed?

Best Answer

For a start the rule says "probably", so it doesn't always apply.

The second point I see here is that if you have to declare one of the three, that's because it's doing something special like allocating memory. In this case, the others wouldn't be empty since they would have to handle the same task (such as copying the content of dynamically allocated memory in the copy constructor or freeing such memory).

So as a conclusion, you shouldn't declare empty constructors or destructors, but it's very likely that if one is needed, the others are needed too.

As for your example: In such a case, you can leave the destructor out. It does nothing, obviously. Usage of smart pointers is a perfect example of where and why the rule of 3 doesn't hold.

It's just a guide for where to take a second look over your code in case you may have forgotten to implement important functionality you might otherwise have missed.