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

Шрифт
Интервал

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

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

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

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

Основной недостаток фигурной инициализации — временами сопровождающее ее удивительное поведение. Такое поведение вырастает из необыкновенно запутанных взаимоотношений между фигурной инициализацией, >std::initializer_list и разрешением перегрузки конструкторов. Их взаимодействие может привести к коду, который, как кажется, должен делать что-то одно, а в результате делает что-то совсем другое. Например, в разделе 1.2 поясняется, что когда переменная, объявленная как >auto, имеет инициализатор в фигурных скобках, то выводимым типом является >std::initializer_list, несмотря на то что другой способ объявления переменной с тем же инициализатором даст более ожидаемый тип. В результате чем больше вам нравится >auto, тем меньше энтузиазма вы должны проявить по отношению к фигурной инициализации.

В вызовах конструктора круглые и фигурные скобки имеют один и тот же смысл, пока в конструкторах не принимают участие параметры >std::initializer_list:

>class Widget {

>public:

> Widget(int i, bool b);   // Конструкторы не имеют параметров

> Widget(int i, double d); // std::initializer_list

>};


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

>Widget w2{10, true}; // Вызов первого конструктора

>Widget w3(10, 5.0);  // Вызов второго конструктора

>Widget w4{10, 5.0};  // Вызов второго конструктора

Если же один или несколько конструкторов объявляют параметр типа >std::initializer_list, вызовы, использующие синтаксис фигурной инициализации, строго предпочитают перегрузки, принимающие >std::initializer_list. Строго. Если у компилятора есть любой способ истолковать вызов с фигурным инициализатором как конструктор, принимающий >std::initializer_ list, он использует именно это толкование. Если класс >Widget выше дополнить конструктором, принимающим, например, >std::initializer_list

>class Widget {

>public:

> Widget(int i, bool b);   // Как и ранее

> Widget(int i, double d); // Как и ранее


> Widget(std::initializer_list il); // Добавлен

> …

>};

то >w2 и >w4 будут созданы с помощью нового конструктора, несмотря на то что тип элементов >std::initializer_list (в данном случае — >long double) хуже соответствует обоим аргументам по сравнению с конструкторами, не принимающими >std::initializer_list! Смотрите сами:

>Widget w1(10, true); // Использует круглые скобки и, как и

>                     // ранее, вызывает первый конструктор

>Widget w2{10, true}; // Использует фигурные скобки, но теперь

>                     // вызывает третий конструктор

>                     // (10 и true преобразуются в long double)

>Widget w3(10, 5.0);  // Использует круглые скобки и, как и

>                     // ранее, вызывает второй конструктор

>Widget w4{10, 5.0};  // Использует фигурные скобки, но теперь

>                     // вызывает третий конструктор

>                     // (10 и 5.0 преобразуются в long double)

Даже то, что в обычной ситуации представляет собой копирующий или перемещающий конструктор, может быть перехвачено конструктором с >std::initializer_list:

>class Widget {

>public:

> Widget(int i, bool b);                         // Как ранее

> Widget(int i, double d);                       // Как ранее

> Widget(std::initializer_list il); // Как ранее


>operator float() const; // Преобразование во float


>};


>Widget w5(w4);            // Использует круглые скобки, вызывает

>                          // копирующий конструктор

>Widget w6{w4};            // Использует фигурные скобки, вызов

>                          // конструктора с std::initializer_list

>                          // (w4 преобразуется во float, а float

>                          // преобразуется в long double)

>Widget w7(std::move(w4)); // Использует круглые скобки, вызывает

>                          // перемещающий конструктор

>Widget w8{std::move(w4)}; // Использует фигурные скобки, вызов

>                          // конструктора с std::initializer_list

>                          // (все, как для w6)

Определение компилятором соответствия фигурных инициализаторов конструкторам с >std::initializer_list настолько строгое, что доминирует даже тогда, когда конструктор с >std::initializer_list с наилучшим соответствием не может быть вызван, например:

>class Widget {

>public:

> Widget(int i, bool b);   // Как ранее

> Widget(int i, double d); // Как ранее

> Widget(std::initializer_list il); // Теперь тип

>                                         // элемента – bool


>}; // Нет функций неявного преобразования


>Widget w


Еще от автора Скотт Мейерс
Эффективное использование STL

В этой книге известный автор Скотт Мейерс раскрывает секреты настоящих мастеров, позволяющие добиться максимальной эффективности при работе с библиотекой STL.Во многих книгах описываются возможности STL, но только в этой рассказано о том, как работать с этой библиотекой. Каждый из 50 советов книги подкреплен анализом и убедительными примерами, поэтому читатель не только узнает, как решать ту или иную задачу, но и когда следует выбирать то или иное решение — и почему именно такое.


Как функции, не являющиеся методами, улучшают инкапсуляцию

Когда приходится инкапсулировать, то иногда лучше меньше, чем большеЯ начну со следующего утверждения: Если вы пишете функцию, которая может быть выполнена или как метод класса, или быть внешней по отношению к классу, Вы должны предпочесть ее реализацию без использования метода. Такое решение увеличивает инкапсуляцию класса. Когда Вы думаете об использовании инкапсуляции, Вы должны думать том, чтобы не использовать методы.Удивлены? Читайте дальше.


Рекомендуем почитать
Изучаем Java EE 7

Java Enterprise Edition (Java EE) остается одной из ведущих технологий и платформ на основе Java. Данная книга представляет собой логичное пошаговое руководство, в котором подробно описаны многие спецификации и эталонные реализации Java EE 7. Работа с ними продемонстрирована на практических примерах. В этом фундаментальном издании также используется новейшая версия инструмента GlassFish, предназначенного для развертывания и администрирования примеров кода. Книга написана ведущим специалистом по обработке запросов на спецификацию Java EE, членом наблюдательного совета организации Java Community Process (JCP)


Платформа J2Me

Эта книга научит вас, как разрабатывать программное обеспечение для платформы J2ME компании «Sun Microsystems». Эта книга придерживается стиля учебного пособия, это не справочное руководство.Цель — дать вам твердую основу в понятиях и техниках, которая даст вам возможность решиться на самостоятельную разработку качественных приложений.


Виртуальная библиотека Delphi

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


Обработка баз данных на Visual Basic.NET

Это практическое руководство разработчика программного обеспечения на Visual Basic .NET и ADO.NET, предназначенное для создания приложений баз данных на основе WinForms, Web-форм и Web-служб. В книге описываются практические способы решения задач доступа к данным, с которыми сталкиваются разработчики на Visual Basic .NET в своей повседневной деятельности. Книга начинается с основных сведений о создании баз данных, использовании языка структурированных запросов SQL и системы управления базами данных Microsoft SQL Server 2000.


Исчерпывающее руководство по написанию всплывающих подсказок

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


Программное обеспечение встроенных систем. Общие требования к разработке и документированию

Embedded system software. General requirements for development and documentationСтандарт подготовлен в развитие ГОСТ Р ИСО/МЭК 12207-99 «Информационная технология. Процессы жизненного цикла программных средств» с целью учета специфики разработки и документирования программного обеспечения встроенных систем реального времени.