Является ли новая функция инициализации членов C++11 при объявлении устаревшими списками инициализации?


С C++11, теперь у нас есть возможность инициализировать члены класса в объявлении заголовка:

class aClass
{
    private:
        int mInt{100};
    public:
         aClass();
        ~aClass();
};

Так что я немного запутался. Традиционно для инициализации членов использовались списки инициализации в конструкторах:

aClass::aClass()
: mInt(100)
{
    ...
}

новая функция инициализации членов C++11 при объявлении сделала списки инициализации устаревшими? Если нет, то каковы преимущества одного над другим? Какие ситуации сделают инициализацию при объявлении выгодной, или списки инициализации выгодны? Когда следует использовать один над другим?

3 57

3 ответа:

нет, они не устарели, как эта статья познакомьтесь с новыми формами инициализации C++11 говорит Инициализация Члена Класса (выделено мной):

имейте в виду, что если один и тот же элемент данных имеет инициализатор члена класса и mem-init в конструкторе, последний имеет приоритет. На самом деле,вы можете воспользоваться этим поведением, указав значение по умолчанию для члена in форма инициализатора члена класса, который будет использоваться, если конструктор не имеет явного mem-init для этого члена. В противном случае mem-init конструктора вступит в силу, переопределяя инициализатор члена класса. этот метод полезен в классах, которые имеют несколько конструкторов

таким образом, хотя в инициализации члена класса является хорошим удобством, это не устраняет необходимость в списках инициализации, но обе функции вместо этого работают вместе, чтобы дайте вам хороший способ указать значения по умолчанию и переопределить их при необходимости. Это, кажется, тоже как Бьярн Страуструп тоже видит, говорит:

Это экономит немного ввода, но реальные преимущества приходят в классы с несколькими конструкторами. Часто все конструкторы используют общий инициализатор для элемента:

и предоставляет пример членов, которые имеют общий инициализатор:

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

и говорит:

тот факт, что hash_algorithm и s имеют одно значение по умолчанию, теряется в беспорядке кода и может легко стать проблемой во время обслуживания. Вместо этого мы можем разложить инициализацию элементов данных:

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

Примечание: недостаток в C++11

есть один недостаток в использовании в инициализации члена класса В C++11, поскольку он делает класс неагрегатным, мы больше не можем использовать агрегатной инициализации что может быть довольно неожиданным. Это не так, в C++14, где это ограничение было снято. Смотрите:C++11 агрегатная инициализация для классов с нестатическими инициализаторами членов для более подробной информации.

нет, они не устарели.

списки инициализации по-прежнему являются единственным способом, если вам нужны аргументы конструкторов для инициализации членов класса.

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

обратите внимание, что если оба присутствуют, инициализация конструктора вступит в силу, переопределяя инициализацию члена класса, что полезно для указания значения по умолчанию для члена класса.

Как я смотрю на это, инициализация в классе является ehancement mem-initializer-lists. В C++03 члены, не перечисленные в списке инициализаторов mem, всегда были по умолчанию инициализируется. это означает конструктор по умолчанию для классов и отсутствие инициализации для примитивных типов.

in-class инициализация просто позволяет указать свои собственные значения по умолчанию. Есть два способа взглянуть на это.

One: если большинство / все конструкторы вашего класса хотят предоставить то же начальное значение для члена, используйте инициализатор в классе для этого члена. Для других членов используйте mem-initializer-lists. Конечно, вам придется использовать их всякий раз, когда начальное значение зависит от аргументов конструктора.

другой: предоставьте инициализатор в классе для всех членов, точно так же, как конструктор по умолчанию вашего класса инициализирует их. Затем mem-initializer-lists в конструкторах, отличных от конструкторов по умолчанию, получают семантику "как он отличается от построенного по умолчанию объект."