Подтвердить что ты не робот

Включена ли новая функция инициализации члена С++ 11 при объявлении, что списки инициализации устарели?

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

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

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

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

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

4b9b3361

Ответ 1

Нет, они не устарели, как в этой статье Ознакомьтесь с новыми форматами инициализации С++ 11 в разделе инициализации члена класса ( внимание мое):

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

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

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

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

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

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

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

Ответ 2

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

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

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

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

Ответ 3

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

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

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

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