0

I have seen following two ways of default initializing the arguments in constructors(which is also applicable in normal free functions too).

#include <string>
using UserDefinedType = std::string;

class MyClass
{
    UserDefinedType m_member;
public:
    // Way - 1
    MyClass(const UserDefinedType &obj = UserDefinedType()) : m_member{ obj } {}
    // Way - 2
    //MyClass(const UserDefinedType &obj = {}) : m_member{ obj }  {}
};
  • I know the first will defensively(explicitly) call the constructor of user defined type. What happens in the second way?
  • Which is the preferable way of practicing with modern compilers(C++11 or later) ?
UserUsing
  • 678
  • 1
  • 5
  • 16

1 Answers1

3

This is a matter of personal preference, there are no implications on what these two options do or invoke. As I guess it is common sense to not repeatedly type types as in

const int three = static_cast<int>(3.14);
const Sub* sub = dynamic_cast<Sub*>(&baseInstance);

which is often written down with auto as

// better, the concrete type is only typed once, less maintainance "burden":
const auto three = static_cast<int>(3.14);
const auto* sub = dynamic_cast<Sub*>(&baseInstance);

you could take this argument and transfer it to the example snippet above:

MyClass(const UserDefinedType &obj = UserDefinedType());

Here, the type is spelled out twice, and that's undesirable. Hence, I recommend going with

// Shorter, not less readable - a default-constructed default instance:
MyClass(const UserDefinedType &obj = {})

Note that in the special case of constructors, it is equally simple to use in-class member initialization together with a default constructor and an additional overload, e.g.

MyClass {
  public:
    MyClass() = default;
    explicit MyClass(const UserDefinedType& obj) : m_member{obj} {}

  private:
    UserDefinedType m_member = {};
};

The advantage of this approach is the low likelihood of introducing bugs when a new constructor overload is added to the class. But this is a nuance. Note, however, that I've marked the single-argument ctor explicit, which is usually considered good practice to prevent accidental implicit conversions.

lubgr
  • 37,368
  • 3
  • 66
  • 117
  • Hi.. thanks for your answer. could you tell me **What happens in the second way?**, what does it call and will it also call the constructor of `UserDefinedType`? – UserUsing Feb 19 '19 at 09:17
  • and your suggested(last code) is only applicable when for all constructors(not only the given case) the `UserDefinedType m_member = {};` should be **true** or **okay to have**. – UserUsing Feb 19 '19 at 09:20
  • @Using That's correct, but I think the situation where a default ctor parameter is bound to one specific ctor overload and is not invariant to the chosen ctor is rather rare. – lubgr Feb 19 '19 at 09:22
  • 1
    And for the first comment: the first and the second syntax are identical in terms of what happens. The curly braces are just another syntactic way to initialize an instance. – lubgr Feb 19 '19 at 09:26