What is the difference between constructor "=default" and the compiler generated constructor in C++?

Dog() = default; is a user declared constructor (not to be confused with a user defined constructor). It is a defaulted default constructor. Typically you would use it when the class has other constructors but you still want the compiler to generate a default constructor (or rather a "defaulted default constructor". This is C++ terminology at its best. Note how the two "default"s have slightly different meaning).

A user declared constructor prevents a class from being an aggregate. From cppreference, only for C++20:

An aggregate is one of the following types:

  • array type
  • class type (typically, struct or union), that has
    • no private or protected direct non-static data members
    • no user-declared or inherited constructors
    • no virtual, private, or protected base classes
    • no virtual member functions

As an example, consider:

#include <iostream>
#include <type_traits>

class Dog {
    int x;
public:
    Dog()=default;
};

class Horse {
    int x;
};

class Swan {
public: 
    int x;
};

class Cow {
public:
    int x;
    Cow() = default;
};

int main() {
    std::cout << std::is_aggregate_v<Dog>;
    std::cout << std::is_aggregate_v<Horse>;
    std::cout << std::is_aggregate_v<Swan>;
    std::cout << std::is_aggregate_v<Cow>;
}

Output

0010

The first two, Dog and Horse, resemble your two versions of Dog. They are not aggregates, because they have private members. Swan is an aggregate, but Cow is not, because it has a user declared constructor.

Something that works with aggregates, but not with non-aggregates, is designated initializers (same cppreference page):

Swan s{.x=3};    // OK
Cow c{.x=4};     // Error: Cow is not an aggregate

TL;DR: I am not aware of a difference between your two Dogs, but in general the presence of a user declared constructor can make a difference.


I'll limit the scope to a default constructor, as in the question's code and tag. For the most part, you'll get the same effect since = default; loosely means "give me the compiler-generated one". It's important to note what exactly having no declaration does:

If there is no user-declared constructor for class X, a non-explicit constructor having no parameters is implicitly declared as defaulted. An implicitly-declared default constructor is an inline public member of its class.

If your declaration changes any of these, it will no longer be the exact same as the implicit one. In the standard, Dog() = default; is a user-declared constructor, but not a user-provided constructor. There are a couple small differences between having a user-declared default constructor and having no constructor.

As mentioned, aggregates were fixed:

struct not_agg {
    not_agg() = delete;
    int x;
};

Before the fix, such a class could be created via aggregate initialization: not_agg{}. Naturally, this also extends to = default;. Per [dcl.init.aggr]:

An aggregate is an array or a class with

  • no user-declared or inherited constructors

There is also rationale given for this change in annex C:

Remove potentially error-prone aggregate initialization which may apply notwithstanding the declared constructors of a class.


An interesting, but very tiny difference is that a class with a user-declared constructor is not allowed to have non-static data members of the same name as the class:

class c {
    int c; // Okay
};

class c2 {
    c2() = default;
    int c2; // Error
};

This is due to [class.mem]/21:

In addition, if class T has a user-declared constructor, every non-static data member of class T shall have a name different from T.


  1. Default declared constructors can be guarded with protected or private access. Not declared default constructors are always inline public members of their classes.
  2. = default constructors are instantiated like usual member functions, may be inline or not, they have strong linkage references in the second case. The compiler creates not declared default constructors as inline member functions with weak linkage references.
  3. As mentioned in the comments, =default constructors are user-defined constructors and their classes are not aggregate types.