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 } {}
};
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.