Default functions in C++11


Sign up for FREE 1 month of Kindle and read all our books for free.

Get FREE domain for 1st year and build your brand new site

C++11 introduced a new use of the default keyword as a way to explicitly tell the compiler that a special member function will use the default implementation.

Introduction

Functions are a set of statements put together that perform a specific task. Member functions include the operators and functions that are members of a class. While the user has to provide these member functions, the compiler generates some of the functions which are known as special member functions.

The special member functions that are generated automatically are: the default constructor, copy constructor and move constructor, copy assignment operator and move assignment operator and a destructor.

In C++11 these special member functions are the only functions that can be defaulted, that is, defined using =default instead of the function body. From C++20 additionally the comparison operators can also be defaulted.

Pre C++11

There are various rules according to which the compiler may or may not automatically generate the special member functions.
If any constructor is declared, then no default constructor is automatically generated. If a destructor is declared, then no default destructor is automatically generated.

If a move constructor or move-assignment operator is explicitly declared, then:
Copy constructor and copy-assignment operator are not automatically generated.
If a copy constructor, copy-assignment operator, move constructor, move-assignment operator, or destructor is declared, then both the move constructor and move-assignment operator are not automatically generated.

Once the defaults are suppressed there is no way to reinstantiate them.

default functions

In C++11, a special member function can be explicitly defined to use the default implementation. The way to do this is to append a =default to the end of the special member function declaration. For example

class foo{
    foo()=default;
};

The =default; is thus part of the special member function definition. This allows us to have the performance benifits of the trivial special member functions with less effort, given that it is what we want.

Example usage

Default constructor

class X{
private:
    int a;
};

X x; // OK, compiler implicitly-defined default constructor is called


class Y{
public:
    Y(int i){
        a = i;
    }
    
private:
    int a;
};

Y y; // error, default constructor Y::Y() doesn't exist


class Z{
public:
    Z()=default; // default
    
    Z(int i){    // user defined constructor
        a = i;
    }
    
private:
    int a;
};

Z z; // OK
Z z2(4); // OK

The code above shows three examples. In the first example class X, no user-defined constructor is provided so the compiler will auto-generate a default constructor that will not take any parameters. In the second example class Y, the compiler will not auto-generate a default constructor, since a user defined constructor is provided. In the third class Z, although the compiler will not provide a default constructor, we can tell it to provide the default implementation to it by using the =default keyword.

Use a standard-defined equality operator

Note that the following works in C++20.
While the equalty operator is not implicitly defined, there is a standard-defined. Here the equality operator compares each data member and determines if they are equal. Two objects are equal if their corresponding members are equal.

consider an example:

#include <iostream>

struct point {
  int x;
  int y;
  bool operator==(const point&) const = default;
};

int main() {
  point p1{1, 2}, p2{3, 4};
  if(p1 == p2){
      std::cout << "equal" << std::endl;
  }
  else{
      std::cout << "unequal" << std::endl;
  }
}

Conclusion

Use of =default allows an explicit way to express as to which of the functions should be automatically provided with default implementation, even if it was stopped from getting one. This is useful when we want to explicitly state that we want to use the default implementation for a special member function.