Has the new C++11 member initialization feature at declaration made initialization lists obsolete?

前端 未结 3 629
遥遥无期
遥遥无期 2020-11-29 18:11

With C++11, we now have the ability to initialize class members in a header declaration:

class aClass
{
    private:
        int mInt{100};
    public:
              


        
相关标签:
3条回答
  • 2020-11-29 18:42

    No, they are not obsolete.

    Initialization lists are still the only way to go if you need a constructor's arguments to initialize your class members.

    class A
    {
      int a=7; //fine, give a default value
    public:
      A();
    };
    
    class B
    {
      int b; 
    public:
      B(int arg) : b(arg) {}
    
      B(int arg, bool b) : b(arg) { ... }
    };
    

    Note that if both are present, the constructor's initialization will take effect, overriding the class member initialization, which is useful to specify a default value for a class member.

    0 讨论(0)
  • 2020-11-29 18:49

    The way I look at it, in-class initialization is an ehancement of mem-initializer-lists. In C++03, members not listed in a mem-initializer-list were always default initialised. This means the default constructor for classes, and no initialization for primitive types.

    In-class initialization simply allows you to specify your own defaults. There are two ways to look at it.

    One: if most/all constructors of your class want to provide the same initial value for a member, use an in-class initializer for that member. For other members, use mem-initializer-lists. You'll of course have to use those whenever the initial value depends on constructor arguments.

    The other one: provide an in-class initializer for all members, exactly how the default constructor of your class would initialise them. Then, mem-initializer-lists in non-default constructors get the semantics of "how it differs from a default-constructed object."

    0 讨论(0)
  • 2020-11-29 18:53

    No, they are not obsolete as this article Get to Know the New C++11 Initialization Forms says in the Class Member Initialization section (emphasis mine):

    Bear in mind that if the same data member has both a class member initializer and a mem-init in the constructor, the latter takes precedence. In fact, you can take advantage of this behavior by specifying a default value for a member in the form of a class member initializer that will be used if the constructor doesn't have an explicit mem-init for that member. Otherwise, the constructor's mem-init will take effect, overriding the class member initializer. This technique is useful in classes that have multiple constructors

    So although in class member initialization is a nice convenience it does not remove the need for initialization lists but both features instead work together to give you a nice way to specify default values and override them when needed. This seems to be also how Bjarne Stroustrup sees it too, he says:

    This saves a bit of typing, but the real benefits come in classes with multiple constructors. Often, all constructors use a common initializer for a member:

    and provides an example of members which have a common initializer:

    class A {
      public:
        A(): a(7), b(5), hash_algorithm("MD5"), s("Constructor run") {}
        A(int a_val) : a(a_val), b(5), hash_algorithm("MD5"), s("Constructor run") {}
        A(D d) : a(7), b(g(d)), hash_algorithm("MD5"), s("Constructor run") {}
        int a, b;
      private:
        HashingFunction hash_algorithm;  // Cryptographic hash to be applied to all A instances
        std::string s;                   // String indicating state in object lifecycle
    };
    

    and says:

    The fact that hash_algorithm and s each has a single default is lost in the mess of code and could easily become a problem during maintenance. Instead, we can factor out the initialization of the data members:

    class A {
      public:
        A(): a(7), b(5) {}
        A(int a_val) : a(a_val), b(5) {}
        A(D d) : a(7), b(g(d)) {}
        int a, b;
      private:
        HashingFunction hash_algorithm{"MD5"};  // Cryptographic hash to be applied to all A instances
        std::string s{"Constructor run"};       // String indicating state in object lifecycle
    };
    

    Note: disadvantage in C++11

    There is one disadvantage to using in class member initialization in C++11 since it makes a class a non-aggregate we can no longer use aggregate initialization which may be rather surprising. This is not the case in C++14 where this restriction was removed. See: C++11 aggregate initialization for classes with non-static member initializers for more details.

    0 讨论(0)
提交回复
热议问题