Скотт Мейерс - Эффективный и современный С++. 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 - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
Рассмотрение инициализаторов в фигурных скобках является единственным отличием вывода типа auto
от вывода типа шаблона. Когда объявленная с использованием ключевого слова auto
переменная инициализируется с помощью инициализатора в фигурных скобках, выведенный тип представляет собой конкретизацию std::initializer_list
. Но если тот же инициализатор передается шаблону, вывод типа оказывается неудачным, и код отвергается:
autox = { 11, 23, 9 }; // Тип x – std::initializer_list
template // Объявление шаблона с параметром
void f( Тparam); // эквивалентно объявлению x
f( { 11, 23, 9 }); // Ошибка вывода типа для Т
Однако, если вы укажете в шаблоне, что param
представляет собой std::initializer_list
для некоторого неизвестного Т
, вывод типа шаблона сможет определить, чем является Т
:
template
void f( std::initializer_list<T >initList);
f( { 11, 23, 9 }); // Вывод int в качестве типа Т, а тип
// initList - std::initializer_list
Таким образом, единственное реальное различие между выводом типа auto
и выводом типа шаблона заключается в том, что auto
предполагает, что инициализатор в фигурных скобках представляет собой std::initializer_list
, в то время как вывод типа шаблона этого не делает.
Вы можете удивиться, почему вывод типа auto
имеет специальное правило для инициализаторов в фигурных скобках, в то время как вывод типа шаблона такого правила не имеет. Но я и сам удивлен. Увы, я не в состоянии найти убедительное объяснение. Но “закон есть закон”, и это означает, что вы должны помнить, что если вы объявляете переменную с использованием ключевого слова auto
и инициализируете ее с помощью инициализатора в фигурных скобках, то выводимым типом всегда будет std::initializer_list
. Особенно важно иметь это в виду, если вы приверженец философии унифицированной инициализации — заключения инициализирующих значений в фигурные скобки как само собой разумеющегося стиля. Классической ошибкой в С++11 является случайное объявление переменной std::initializer_list
там, где вы намеревались объявить нечто иное. Эта ловушка является одной из причин, по которым некоторые разработчики используют фигурные скобки в инициализаторах только тогда, когда обязаны это делать. (Когда именно вы обязаны так поступать, мы рассмотрим в разделе 3.1.)
Что касается С++ 11, то на этом история заканчивается, но для С++14 это еще не конец. С++14 допускает применение auto
для указания того, что возвращаемый тип функции должен быть выведен (см. раздел 1.3), а кроме того, лямбда-выражения С++ 14 могут использовать auto
в объявлениях параметров. Однако такое применение auto
использует вывод типа шаблона, а не вывод типа auto
. Таким образом, функция с возвращаемым типом auto
, которая возвращает инициализатор в фигурных скобках, компилироваться не будет:
auto createInitList() {
return { 1, 2, 3 }; // Ошибка: невозможно вывести
} // тип для { 1, 2, 3 }
То же самое справедливо и тогда, когда auto
используется в спецификации типа параметра в лямбда-выражении С++14:
std::vector v;
auto resetV =
[&v](const auto& newValue) { v = newValue; }; // C++14
resetV( { 1, 2, 3 }); // Ошибка: невозможно вывести
// тип для { 1, 2, 3 }
• Вывод типа auto
обычно такой же, как и вывод типа шаблона, но вывод типа auto
, в отличие от вывода типа шаблона, предполагает, что инициализатор в фигурных скобках представляет std::initializer_list
.
• auto
в возвращаемом типе функции или параметре лямбда-выражения влечет применение вывода типа шаблона, а не вывода типа auto
.
1.3. Знакомство с decltype
decltype
— создание странное. Для данного имени или выражения decltype
сообщает вам тип этого имени или выражения. Обычно то, что сообщает decltype
, — это именно то, что вы предсказываете. Однако иногда он дает результаты, которые заставляют вас чесать в затылке и обращаться к справочникам или сайтам.
Мы начнем с типичных случаев, в которых нет никаких подводных камней. В отличие от того, что происходит в процессе вывода типов для шаблонов и auto
(см. разделы 1.1 и 1.2), decltype
обычно попугайничает, возвращая точный тип имени или выражения, которое вы передаете ему:
const int i = 0; // decltype(i) - const int
bool f(const Widget& w); // decltype(w) - const Widget&
// decltype(f) - bool(const Widget&)
struct Point {
int x, y; // decltype (Point::x) - int
}; // decltype(Point::y) – int
Widget w; // decltype(w) – Widget
if (f(w)) … // decltype (f(w)) — bool
template // Упрощенная версия std::vector
class vector {
public:
…
T& operator[](std::size_t index);
};
vector v; // decltype(v) – vector
…
if (v[0] == 0) …
// decltype(v[0]) - int&
Видите? Никаких сюрпризов.
Пожалуй, основное применение decltype
в С++11 — объявление шаблонов функций, в которых возвращаемый тип функции зависит от типов ее параметров. Предположим, например, что мы хотим написать функцию, получающую контейнер, который поддерживает индексацию с помощью квадратных скобок (т.е. с использованием “ []
”) с индексом, а затем аутентифицирует пользователя перед тем как вернуть результат операции индексации. Возвращаемый тип функции должен быть тем же, что и тип, возвращаемый операцией индексации.
operator[]
для контейнера объектов типа Т
обычно возвращает Т&
. Например, это так в случае std::deque
и почти всегда — в случае std::vector
. Однако для std::vector
оператор operator[]
не возвращает bool&
. Вместо этого он возвращает новый объект. Все “почему” и “как” данной ситуации рассматриваются в разделе 2.2, но главное здесь то, что возвращаемый оператором operator[]
контейнера тип зависит от самого контейнера.
decltype
упрощает выражение этой зависимости. Вот пример, показывающий применение decltype
для вычисления возвращаемого типа. Этот шаблон требует уточнения, но пока что мы его отложим.
template // Работает, но
autoauthAndAccess(Container& с, Index i) // требует
->decltype(c[i]) // уточнения
{
authenticateUser();
return c[i];
}
Использование auto
перед именем функции не имеет ничего общего с выводом типа. На самом деле оно указывает, что использован синтаксис С++11 — завершающий возвращаемый тип (trailing return type), т.е. что возвращаемый тип функции будет объявлен после списка параметров (после “ ->
”). Завершающий возвращаемый тип обладает тем преимуществом, что в спецификации возвращаемого типа могут использоваться параметры функции. В authAndAccess
, например, мы указываем возвращаемый тип с использованием с
и i
. Если бы возвращаемый тип, как обычно, предшествовал имени функции, c
и i
были бы в нем недоступны, поскольку в этот момент они еще не были объявлены.
Интервал:
Закладка: