2016-07-17 2 views
2

Другой вопрос на C++, я пытаюсь выяснить, каковы эффекты использования «=» при построении объектов. Рассмотрите:Эффекты использования «=» в построении объекта

class Foo { 
    private: 
     int bar; 
     int baz; 

    public: 
     Foo(int bar, int baz) 
      :bar(bar), baz(baz) {} 
}; 

int main() { 
    Foo foo1{4, 2}; 
    Foo foo2 = {4, 2}; 
    Foo foo3 = Foo{4, 2}; // I prefer this one for aesthetic reasons. 

    return 0; 
} 

В чем отличия, и какие из них следует придерживаться как наилучшая практика?

Кроме того, пока мы находимся на тему лучших практик, я слышу, что добавление explicit к конструкторам - это хорошая идея из-за странного поведения с неявными преобразованиями. Поэтому я добавил explicit конструктору Foo:

public: 
     explicit Foo(int bar, int baz) 
      :bar(bar), baz(baz) {} 

Вдруг это:

Foo foo2 = {4, 2}; 

Не удается скомпилировать с ошибкой:

error: chosen constructor is explicit in copy-initialization 

Почему?

+1

Две отличия, которые имеют значение: 1) Как вы видели, инициализация копирования не работает с явными конструкторами. 2) 'auto' выводит' std :: initializer_list' по-разному между копией и прямой инициализацией. В остальном он становится спорным в C++ 17. – ildjarn

+3

'Foo foo3 = Foo {4, 2}; // Я предпочитаю это. «Я понятия не имею, почему. Понятно, что это предполагает совершенно бессмысленную дополнительную копию, хотя на самом деле хороший оптимизирующий компилятор отменит вашу ошибку. Но это просто выглядит многословным и уродливым. Зачем писать больше, чем нужно, когда это избыточно?'Foo foo {4, 2};' превосходит. –

+2

«Я слышу добавление явного к конструкторам ...» - помимо того, что я был ужасно одевающимся, сделал невменяемый автор, где бы вы ни слышали, что упоминаете * почему * они считают это хорошей идеей? Вы согласны, не согласны или просто не понимаете этого оправдания? Наконец, [это описание 'explicit'] (http://en.cppreference.com/w/cpp/language/explicit) заслуживает рассмотрения. – WhozCraig

ответ

8

What are the differences

Foo foo1{4, 2}; 

Это direct initialization (2).

Direct initialization is performed in the following situations:

2) during list-initialization sequence, if no initializer-list constructors are provided and a matching constructor is accessible, and all necessary implicit conversions are non-narrowing.


Foo foo2 = {4, 2}; 

Это copy list initialization (6). Явные конструкторы не рассматриваются для инициализации не-прямого списка. Это объясняет, почему программа не скомпилировалась при явной экспликации конструктора.

copy-list-initialization (only non-explicit constructors may be called)

6) initialization of a named variable with a braced-init-list after an equals sign


Foo foo3 = Foo{4, 2}; 

Это direct list initialization (2) временного объекта, а затем copy initialization (1) от временного.

direct-list-initialization (both explicit and non-explicit constructors are considered)

2) initialization of an unnamed temporary with a braced-init-list


Copy initialization is performed in the following situations:

2) when a named variable (automatic, static, or thread-local) of a non-reference type T is declared with the initializer consisting of an equals sign followed by an expression.


Первый проще, и именно поэтому я предпочитаю его.

Второй требует неявного конструктора, но в остальном это хорошо.

Третий включает в себя повторение типа (нарушает DRY) и создает ненужное временное (на практике копия может быть удалена оптимизатором, но тип должен быть скопирован).

I hear adding explicit to constructors is a Good Idea™. So I added explicit to the constructor of Foo

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