1

What are the pro and cons of declaring always defaulted constructors for each non user-defined constructor?

Consider a class with a user-defined constuctor which does not need other user-defined constructors, it would be:

class Foo
{
public:
   Foo() { // user-defined declaration }
   Foo(const Foo&) = default;
   Foo(Foo&&) noexcept = default;
   ~Foo() = default;

   Foo& operator=(const Foo&) = default;
   Foo& operator=(Foo&&) = default;
}

There are other actual advantages/disadvantages of doing that?

Moia
  • 2,216
  • 1
  • 12
  • 34

2 Answers2

5

Several disadvantages of the top of my head:

  1. You can forget special functions. The example you show doesn't define copy/move assignment operators.
  2. declaring the destructor as default in the header will make it so you are unable to use forward declared classes in e.g. a std::unique_ptr member of a class. You can mitigate this by either including the class definition (leading to an eventual overall increase in (re)build time for non-trivial projects, especially when the not forward declared class changes often). You can mitigate this by moving the = default to a definition in a source file.
  3. (subjective) It overloads the class definition visually: every capable C++ developer knows these are usually automatically generated anyway, so they provide no extra information although they take time to read and understand. Note that I'm only talking about the "everything default" case, so no special functions are deleted or some such.
  4. Adding a move-only data member will require you to also remove the =default copy constructor and assignment operators. Whether or not you want this to be necessary is partially a question of style, but this does lead to more involved code changes, especially when refactoring classes like these in a more general sense.
  5. If any other special compiler-generated functions are added to later versions of C++, you miss them automatically, whereas otherwise you'd have already had them implicitly defined.

There are probably some more, rising in subtility level beyond these.

rubenvb
  • 74,642
  • 33
  • 187
  • 332
  • Note that regarding #2, omitting the declaration altogether instead of making it `= default` has exactly the same effect. – Angew is no longer proud of SO Apr 19 '18 at 07:13
  • @rubenvb you're right, I forgot assignment operators. Edited. – Moia Apr 19 '18 at 07:14
  • @Angew True, yet I like the notion of using `override` on inheriting classes' destructors to ensure the class hierarchy has proper virtual destructors. Although that does mean I need to provide copy/move construction/assignment declarations as well... – rubenvb Apr 19 '18 at 07:14
  • @Moia you have too many `=` in those. But I would leave them out of the question. Then my number one becomes all the more pertinent. – rubenvb Apr 19 '18 at 07:15
5

There are no advantages. It merely demonstrates to the reader of your code that you don't know how the C++ compiler works. If you enforce this as a policy, you are also vulnerable to changes in future C++ standards.

An exception is using

virtual ~Foo() = default;

in a base class, where we introduce polymorphism which can help memory management.

Another class of exceptions are cases where you might want to change the access specifier for a defaultable function:

protected:
    Foo foo() = default;

The explicit example I give here can be useful if you only want to use a class via inheritance, but don't want to make it a polymorphic type.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
  • 2
    "can help memory management" should read "avoids undefined behaviour". There is nothing memory management related in a proepr virtual destructor. It is straight undefined behaviour to delete a base class pointer pointing to a derived class if that base class doesn't have a virtual destructor. – rubenvb Apr 19 '18 at 07:16
  • @Bathsheba could you provide a scenario for the defaulted protected constructor please? – Moia Apr 19 '18 at 07:22
  • 1
    @Moia. Added at the end. – Bathsheba Apr 19 '18 at 07:23
  • @rubenvb So it can help not require you to jump through hoops to figure out the concrete type of the instance to avoid that UB, so it can help memory management as this answer said. –  Apr 19 '18 at 07:24