What's the point of deleting default class constructor?

Solution 1:

Consider the following class:

struct Foo {
    int i;
};

This class is an aggregate, and you can create an instance with all three of these definitions:

int main() {
    Foo f1;     // i uninitialized
    Foo f2{};   // i initialized to zero
    Foo f3{42}; // i initialized to 42
}

Now, let's say that you don't like uninitialized values and the undefined behaviour they could produce. You can delete the default constructor of Foo:

struct Foo {
    Foo() = delete;
    int i;
};

Foo is still an aggregate, but only the latter two definitions are valid -- the first one is now a compile-time error.

Solution 2:

There are a few reasons to delete the default constructor.

  1. The class is purely static, and you don't want users instantiating a class with only static methods/members. An example of such a class might be one that implements the factory design pattern using only static methods to create new classes.
  2. It wouldn't make sense for the class to have a default constructor (Since it requires parameters/There are no default values that would make sense for the class). In this case, the = delete is a style thing, as @HolyBlackCat said, but it does clarify your intent by telling the client code to only call the constructor with the parameters.
  3. You do not want uninitialized data for an aggregate class.

If the second statement was unclear, consider the following example:

class A
{
public:
   //A() = delete; 
   A(int, int) {};
};

If you tried to call the default constructor right now, you would get an error that would look something like (GCC 7.2):

error: no matching function for call to 'A::A()'

However, if you uncommented the line with the = delete, then you would get the following:

error: use of deleted function 'A::A()'

This makes it explicitly clear that one is trying to use a deleted constructor in comparison to the other error, which is somewhat unclear.

Solution 3:

Sometimes classes aren't intended to be instantiated.

One example that hasn't been mentioned so far are 'trait' classes. For example, consider std::char_traits, although the standard hasn't said that its default constructor needs to be deleted, its default constructor is of little use because the class itself is empty, all its functions are static and it doesn't need to be instantiated to use the type aliases it provides.

Trait classes are usually only ever used to support other classes (usually other template classes), hence it can often make sense to delete their default constructor - to reinforce the notion that they're just a helper type and not really supposed to be used like an object.

Solution 4:

Multiple default choices

Deleting the default constructor of a class is a good idea when there are multiple choices for the default or uninitialised state. For example, suppose I have a class,

template<typename F>
class Polynomial;

which represents a polynomial over a field, F. In this case, there are many choices for a default value of the polynomial. One could be the identity for polynomials under addition, i.e. zero, but we could also have the multiplicative identity, unity. It depends how the user intends to reason about the class and how it is used.


No default choice

The other notable case is when instead of having multiple default states that could make sense, we have none. For example, suppose we have a class representing a manifold or surface.

What then is Manifold()? It's an empty space, with nothing, no surface, no notion of distance or metric. But then it doesn't make sense to think of it as a manifold, but rather perhaps something more general like a topological space.

So, in this case, I would opt to delete the default constructor as well.