2015-07-20 2 views
0

Использование C++ стандарт 11, я могу инициализировать члены класса двумя способами:Лучший способ инициализации членов класса?

class MyClass 
{ 
private: 
    int a = 5; 
}; 

или

class MyClass 
{ 
private: 
    int a; 
public: 
    MyClass() 
    { 
     a = 5; 
    } 
}; 

Является либо метод превосходит другой по какой-либо причине, или это скорее индивидуальный стиль?

+1

Вам не хватает примера, используя инициализаторы ctor. Второй пример - это просто присваивать значение 'a', поскольку оно уже инициализировано. Менее важно для интегральных типов, более важных для сложных. –

+1

@KaiSchmidt: CaptionObvious ссылается на это: 'MyClass(): a (5) {}', и он имел в виду, что вы "* присваиваете значение' a' ** после того, как ** оно уже было инициализировано * ". –

+0

Я вижу. Должен ли я использовать этот метод для инициализации более одного члена, как бы выглядел синтаксис? –

ответ

3

Второй пример: не Инициализация.

Итак, из двух примеров первым является лучший способ инициализации членов класса.

Традиционный способ инициализирует выглядит так:

class MyClass 
{ 
private: 
    int a; 
public: 
    MyClass() 
     : a(5) 
    {} 
}; 

Хотя мы теперь имеем встроенные инициализаторов, как и в первом примере, так как C++ 11.

+0

Согласно моему второму вопросу, лучше ли использовать инициализаторы ctor или встроенные? –

+0

@KaiSchmidt: «Лучше» в соответствии с какой метрикой? Для кого? В какой ситуации? Вы не указали никаких условий, целей или критериев. Поэтому на ваш вопрос невозможно ответить. Прекратите искать жесткие и быстрые правила. –

+0

Просто используйте все, что проще, они разрешают один и тот же байтовый код. Списки ctor init могут использоваться на очень старых компиляторах, но это его единственное преимущество, и это мгновенно перевешивает, если вы предпочитаете встраивание даже немного –

1

This page from the Standard C++ Foundation предполагает, что при прочих равных условиях вы должны использовать список инициализаторов. То есть:

Предпочитают

class Foo { 
    public: 
    Foo(int bar) : m_bar(bar) { } 
    private: 
    int m_bar; 
}; 

над

class Foo { 
    public: 
    Foo(int bar) { 
     m_bar = bar; 
    } 
    private: 
    int m_bar; 
}; 

Их обоснование:

Рассмотрим следующий конструктор, инициализирующий объект члена x_ с помощью списка инициализации: Fred::Fred() : x_(whatever) { }. Наиболее предпочтительным преимуществом этого является улучшение производительности. Для примера , если выражение типа того же типа, что и член , переменная x_, результат любого выражения сконструирован непосредственно внутри x_ - компилятор не делает отдельную копию объекта . Даже если типы не совпадают, компилятор обычно способен выполнять лучшую работу с списками инициализации, чем с заданиями .

Другой (неэффективный) способ построения конструкторов - через назначение, такой как: Fred::Fred() { x_ = whatever; }. В этом случае выражение независимо от того, что вызывает создание отдельного временного объекта, и этот временный объект передается в оператор присваивания объекта x_. Затем этот временный объект разрушается на ;. Это неэффективно.

Как будто это было не так плохо, есть еще один источник неэффективности при использовании задания в конструкторе: объект члена получит полностью построенный конструктор по умолчанию, и это может, например, выделить некоторое значение по умолчанию объем памяти или открыть файл по умолчанию . Вся эта работа может быть напрасной, если любое выражение и/или оператор присваивания заставляет объект закрыть этот файл и/или освободить эту память (например,, если конструктор по умолчанию не выделял достаточно большой пул памяти или если он открыл неправильный файл).

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

Что касается инициализации по умолчанию (например, Foo(): m_bar(5) { }) Я хотел бы также пойти с подходом списка инициализатора (или инициализации подходом членов в C++ 11) только для совместимости с указанной выше директивой.

Смежные вопросы