Скотт Мейерс - Эффективный и современный С++. 42 рекомендации по использованию С++11 и С++14
- Название:Эффективный и современный С++. 42 рекомендации по использованию С++11 и С++14
- Автор:
- Жанр:
- Издательство:Вильямс
- Год:2016
- Город:Москва
- ISBN:978-5-8459-2000-3
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Скотт Мейерс - Эффективный и современный С++. 42 рекомендации по использованию С++11 и С++14 краткое содержание
В книге рассматриваются следующие темы. Освоение С++11 и С++14 — это больше, чем просто ознакомление с вводимыми этими стандартами возможностями (например, объявлениями типов
, семантикой перемещения, лямбда-выражениями или поддержкой многопоточности). Вопрос в том, как использовать их эффективно, чтобы создаваемые программы были корректны, эффективны и переносимы, а также чтобы их легко можно было сопровождать. Именно этим вопросам и посвящена данная книга, описывающая создание по-настоящему хорошего программного обеспечения с использованием C++11 и С++14 — т.е. с использованием современного С++.
■ Преимущества и недостатки инициализации с помощью фигурных скобок, спецификации
, прямой передачи и функций
интеллектуальных указателей
■ Связь между
,
, rvalue-ссылками и универсальными ссылками
■ Методы написания понятных, корректных,
лямбда-выражений
■ Чем
отличается от
, как они используются и как соотносятся с API параллельных вычислений С++
■ Какие из лучших методов “старого” программирования на С++ (т.е. С++98) должны быть пересмотрены при работе с современным С++
Более чем 20 лет книги
серии
являются критерием уровня книг по программированию на С++. Понятное пояснение сложного технического материала принесло ему всемирную известность. Он всегда самый желанный гость на международных конференциях, а его услуги консультанта широко востребованы во всем мире.
Скотт Мейерс Эффективный и современный С++, После изучения основ С++ я перешел к изучению того, как применять С++ в промышленном программировании, с помощью серии книг Скотта Мейерса Эффективный С++. Эффективный и современный С++ — наиболее важная из книг серии, предлагающая ключевые рекомендации, стили и идиомы, позволяющие эффективно использовать современный С++. Вы еще не купили эту книгу? Сделайте это прямо сейчас. Герб Саттер,
глава Комитета ISO по стандартизации С++, специалист в области архитектуры программного обеспечения на С++ в Microsoft
Эффективный и современный С++. 42 рекомендации по использованию С++11 и С++14 - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
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 без аргументов
Таким образом, в пользу фигурной инициализации имеется много “за”. Это синтаксис, который может использоваться в самых разнообразных контекстах, предотвращающий неявные сужающие преобразования и не подверженный неприятностям с синтаксическим анализом С++. Тройное “за”! Так почему бы не озаглавить раздел просто “Используйте синтаксис фигурной инициализации”?
Основной недостаток фигурной инициализации — временами сопровождающее ее удивительное поведение. Такое поведение вырастает из необыкновенно запутанных взаимоотношений между фигурной инициализацией, 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 {10, 5.0}; // Ошибка! Требуется сужающее преобразование
Здесь компилятор игнорирует первые два конструктора (второй из которых в точности соответствует обоим типам аргументов) и пытается вызвать конструктор, получающий аргумент типа std::initializer_list
. Вызов этого конструктора требует преобразования значений int(10)
и double(5.0)
в bool
. Оба эти преобразования являются сужающими ( bool
не может в точности представить ни первое, ни второе значения), а так как сужающие преобразования запрещены в фигурных инициализаторах, вызов является некорректным, и код отвергается.
Интервал:
Закладка: