57

I'm preparing for my CPP exam and one of the question is: Can you delete default class constructor and if so, what would be the reason to do so? OK, so obviously you can do it:

class MyClass 
{ 
  public: 
    MyClass() = delete; 
};

but I do not understand why would you do it?

Arnav Borborah
  • 11,357
  • 8
  • 43
  • 88
Derek Johnson
  • 717
  • 1
  • 5
  • 9
  • 4
    @DerekJohnson: What about this one: https://stackoverflow.com/q/13654927/27678 – AndyG Feb 07 '18 at 13:15
  • @acraig5075 If you provide another constructor then the default constructor is not generated, so there is no need to delete it. – Richard Critten Feb 07 '18 at 13:15
  • 1
    @AndyG honestly if you read through this it actually does not answer this questions. From someone's comment: "I honestly don't understand how this answers the main question. The question in the title and OP's first question in the post was: When/why would I want to explicitly delete my constructor? " – Derek Johnson Feb 07 '18 at 13:18
  • @acraig5075 You should not answer questions in the comment field. – pipe Feb 07 '18 at 15:17

4 Answers4

82

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.

Quentin
  • 62,093
  • 7
  • 131
  • 191
  • 20
    Or instead, just do `struct Foo { int i = 0; };`. – T.C. Feb 07 '18 at 20:20
  • 7
    @T.C. Is right, but i raise the counterpoint that this example is minimal, there could be more elaborate situations where this could come in handy. I myself can't come up with one, though. – Machinarius Feb 08 '18 at 00:10
  • 1
    @T.C. `Foo` is no longer an aggregate then; this is not an issuer per se, but we'd rather explicit it. (nota: only for C++11 & C++14) – YSC Feb 08 '18 at 10:58
  • @YSC Only for C++11, you mean. – T.C. Feb 09 '18 at 08:14
  • @T.C. Ho I got mixed up in my pdfs. Yes you're right, only C++11. – YSC Feb 09 '18 at 09:04
  • 1
    Since C++20, `Foo` or any type with a deleted default constructor is no longer considered an aggregate type. – 303 Sep 22 '21 at 19:17
50

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.

Arnav Borborah
  • 11,357
  • 8
  • 43
  • 88
  • 5
    In the second case it would be deleted automatically, so `= delete` would be a style thing. – HolyBlackCat Feb 07 '18 at 13:14
  • And in the first case, why are you making a class instead of a namespace? – Quentin Feb 07 '18 at 13:17
  • 1
    @Quentin Could maybe be a class template with only static members. – aschepler Feb 07 '18 at 13:18
  • 4
    @aschepler fair enough. Namespace templates would be cool though. – Quentin Feb 07 '18 at 13:21
  • 6
    @HolyBlackCat No… it would be *undeclared*, not *deleted*. A subtle but sometimes important distinction. Practically speaking, an attempt to use the former will cause an error like "No matching constructor in call…", while the latter will cause an error like "Default constructor is deleted in call …" (I'm too lazy to check the exact wording though, which depends on the compiler anyway.) – Arne Vogel Feb 07 '18 at 15:10
  • @ArneVogel Now I'm curious. Is there any difference except for the wording of error messages? – HolyBlackCat Feb 07 '18 at 15:13
  • 7
    @HolyBlackCat A deleted func. participates in overload resolution. E.g. with `X(const X&)` user-declared, no move c'tor is implicitly declared, but `X(std::move(anotherX))` would still work, selecting the copy c'tor as closest match. But if the move c'tor is deleted, this code becomes ill-formed. Also, if you have a variadic c'tor e.g. `X(Args&&...)`, this can be used to construct the object w/o arguments, but not if there is a deleted `X()`. [reference](https://stackoverflow.com/questions/15181424/why-does-deleting-move-constructor-cause-vector-to-stop-working) – Arne Vogel Feb 07 '18 at 15:55
  • @HolyBlackCat it is also possible to define a class that as far as C++ is concerned, is sensible to default-construct, but the higher-level semantics of your program still say has no sensible default values anyway. `= delete` makes this part clear and enforces it when your logical requirements are stricter than those imposed by the language. – Alex Celeste Feb 08 '18 at 09:28
  • 1
    Explicit delete also prevents programmers from mistakenly adding it in a hurry. – Agent_L Feb 08 '18 at 09:54
6

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.

Pharap
  • 3,826
  • 5
  • 37
  • 51
5

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.

user1997744
  • 411
  • 4
  • 16