Читать «Эффективный и современный С++. 42 рекомендации по использованию С++11 и С++14» онлайн - страница 40

Скотт Мейерс

std::vector<int> v{ 1, 3, 5 }; // v изначально содержит 1, 3, 5

Фигурные скобки могут также использоваться для указания значений инициализации по умолчанию для нестатических членов-данных. Эта возможность — новая в С++11 — может использоваться с синтаксисом “=” но не с круглыми скобками:

class Widget {

 …

private:

 int x{ 0 }; // OK, значение x по умолчанию равно 0

 int y = 0;  // Тоже OK

 int z(0);   // Ошибка!

};

С другой стороны, некопируемые объекты (например, std::atomic — см. раздел 7.6) могут быть инициализированы с помощью фигурных или круглых скобок, но не с помощью знака равенства:

std::atomic<int> ai1{ 0 }; // OK

std::atomic<int> ai2(0);   // OK

std::atomic<int> ai3 = 0;  // Ошибка!

Легко понять, почему фигурная инициализация названа “унифицированной'”. Из трех способов обозначения выражений инициализации только фигурные скобки могут использоваться везде.

Новая возможность фигурной инициализации заключается в том, что она запрещает неявные сужающие преобразования среди встроенных типов. Если значение выражения в фигурном инициализаторе не может быть гарантированно выражено типом инициализируемого объекта, код не компилируется:

double x, y, z;

int sum1{ x + y + z }; // Ошибка! Сумма double может

                       // не выражаться с помощью int

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

int su.2(x+y+z) ; // OK (значение выражения усекается до int)

int sum3 = x+y+z; //

Обращает на себя внимание еще одна особенность фигурной инициализации — она не подвержена наиболее неприятному анализу в С++. Побочным эффектом правила С++, согласно которому все, что в ходе синтаксического анализа может рассматриваться как объявление, должно рассматриваться как таковое, является так называемый наиболее неприятный анализ, который чаще всего досаждает разработчикам, когда они хотят создать объект по умолчанию, а в результате получают объявление функции. Корень проблемы кроется в том, что если вы хотите вызвать конструктор с аргументом, вы делаете это примерно следующим образом:

Widget w1(10); // Вызов конструктора Widget с аргументом 10

Но если вы пытаетесь вызвать конструктор Widget без аргументов с помощью аналогичного синтаксиса, то фактически объявляете функцию вместо объекта:

Widget w2(); // Синтаксический анализ рассматривает это как

             // объявление функции w2, возвращающей Widget!

Функции не могут быть объявлены с использованием фигурных скобок для списка параметров, так что конструирование объекта по умолчанию с применением фигурных скобок такой проблемы не вызовет:

Widget w3{}; // Вызов конструктора Widget без аргументов

Таким образом, в пользу фигурной инициализации имеется много “за”. Это синтаксис, который может использоваться в самых разнообразных контекстах, предотвращающий неявные сужающие преобразования и не подверженный неприятностям с синтаксическим анализом С++. Тройное “за”! Так почему бы не озаглавить раздел просто “Используйте синтаксис фигурной инициализации”?