dimanche 23 juin 2019

C++11: Can defaulting default constructor lead to partially initialized class?

In C++11 and beyond it seems like because of the differences between default and value initialization depending on how I define my class the result of initialization can be different. For example, look at the classes below or http://coliru.stacked-crooked.com/a/b45acc5acf847e73:

#include <iostream>
#include <string>
#include <vector>

class ClassWithDefaultedConstructor {
 public:
  ClassWithDefaultedConstructor() = default;
  int GetInt() const { return member_int_; }
  bool GetBool() const { return member_bool_; }
  std::string GetString() const { return member_string_; }

 private:
  int member_int_;
  bool member_bool_;
  std::string member_string_;
  int member_int_array_[5];
};

class ClassWithUserProvidedDefaultConstructor {
 public:
  ClassWithUserProvidedDefaultConstructor() : member_int_() {}
  int GetInt() const { return member_int_; }
  bool GetBool() const { return member_bool_; }
  std::string GetString() const { return member_string_; }

 private:
  int member_int_;
  bool member_bool_;
  std::string member_string_;
  int member_int_array_[5];
};

class ClassWithDefaultedConstructorAndDefaultMemberInitializers {
 public:
  ClassWithDefaultedConstructorAndDefaultMemberInitializers() = default;
  int GetInt() const { return member_int_; }
  bool GetBool() const { return member_bool_; }
  std::string GetString() const { return member_string_; }

 private:
  int member_int_{};
  bool member_bool_{};
  std::string member_string_;
  int member_int_array_[5]{};
};

int main()
{
    std::cout << "Hello World!" << std::endl;

    // Default initialization: int and bool members will have indeterminate values
    ClassWithDefaultedConstructor default_init1;
    // Value initialization: int and bool members will be zero-initialized
    ClassWithDefaultedConstructor value_init1{};

    // Default initialization: member_int_ is value initialized to 0 in constructor
    // member initiazer list but member_bool_ and member_int_array_ have indeterminate values
    ClassWithUserProvidedDefaultConstructor default_init2;
    // Value initialization: member_bool_ and member_int_array_ are default initialized
    // and have indeterminate values
    ClassWithUserProvidedDefaultConstructor value_init2{};

    // Default initialization: int and bool members are value initialized to 0 because
    // of the default member initializers value initializing them
    ClassWithDefaultedConstructorAndDefaultMemberInitializers default_init3;
    // Value initialization: same as if no default member initializers were used
    ClassWithDefaultedConstructorAndDefaultMemberInitializers value_init3{};
}

So depending on how a client of my class chooses to declare an object (with or without an initializer) the starting state of my object will be different. Is this true? I come across a lot of code in open source projects where members of class type from the standard library such as std::string aren't initialized in the user-provided default constructor. If so it seems like I should either provide default member initializers for all members or define a default constructor that initializes all members. Is there any difference between defaulting the default constructor and using default member initializers for all members vs defining a default constructor that initializes all members in the member initializer list?

Aucun commentaire:

Enregistrer un commentaire