Скотт Мейерс - Эффективный и современный С++. 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 - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
error: aggregate 'TD< int> xType' has incomplete type and
cannot be defined
error: aggregate 'TD< const int *> yType' has incomplete type
and cannot be defined
Другой компилятор выдает ту же информацию, но в несколько ином виде:
error: 'xType' uses undefined class 'TD< int>'
error: 'yType' uses undefined class 'TD< const int *>'
Если не учитывать разницу в оформлении, все протестированные мною компиляторы при использовании этого метода генерировали сообщения об ошибках с интересующей меня информацией о типах.
Подход с использованием функции вывода для отображения сведений о типе может быть использован только во время выполнения программы, зато он предоставляет полный контроль над форматированием вывода. Вопрос в том, чтобы создать подходящее для вывода текстовое представление информации. “Без проблем, — скажете вы. — Нам на помощь придут typeid
и std::type_info::name
”. В наших поисках информации о выведенных для x
и y
типах можно написать следующий код:
std::cout << typeid(x).name()<< '\n'; // Выведенные типы
std::cout << typeid(y).name()<< '\n'; // для x и y
Этот подход основан на том факте, что вызов typeid
для такого объекта, как x
или y
, дает объект std: :type_info
, а он имеет функцию-член name
, которая дает С-строку (т.е. const char*
), представляющую имя типа.
Не гарантируется, что вызов std::type_info::name
вернет что-то разумное, но его реализации изо всех сил пытаются быть полезными. Уровень этой полезности варьируется от компилятора к компилятору. Компиляторы GNU и Clang, например, сообщают, что тип x
— это “ i
” а тип y
— “ PKi
”. Эти результаты имеют смысл, если вы будете знать, что “ i
” у данных компиляторов означает “ int
”, а “ PK
” — “указатель на константу”.
(Оба компилятора поддерживают инструмент c++filt
, который расшифровывает эти имена.) Компилятор Microsoft генерирует менее зашифрованный вывод: “ int
” для x
и “i nt const *
”для y
.
Поскольку это корректные результаты для типов x
и y
, вы можете подумать, что задача получения информации о типах решена, но не делайте скоропалительных выводов. Рассмотрим более сложный пример:
template // Шаблонная функция,
void f(const T& param); // вызываемая далее
std::vector createVec(); // Фабричная функция
const auto vw = createVec(); // Инициализация vw возвратом
// фабричной функции
if (!vw.empty()) {
f(&vw[0]); // Вызов f
}
Этот код, включающий пользовательский тип ( Widget
), контейнер STL ( std::vector
) и переменную auto ( vw
), является более представительным и интересным примером. Было бы неплохо узнать, какие типы выводятся для параметра типа шаблона Т
и для параметра param функции f
.
Воспользоваться typeid
в этой задаче достаточно просто. Надо всего лишь добавить немного кода в функцию f для вывода интересующих нас типов:
template
void f(const T& param) {
using std::cout;
// Вывод в поток cout типа T:
cout << "Т = " << typeid(T).name()<< '\n';
// Вывод в поток cout типа param:
cout << "param = " << typeid(param).name()<< '\n';
}
Выполнимые файлы, полученные с помощью компиляторов GNU и Clang, дают следующий результат:
Т = PK6Widget
param = PK6Widget
Мы уже знаем, что в этих компиляторах PK
означает указатель на константу, так что вся загадка — в цифре 6
. Это просто количество символов в следующем за ней имени класса ( Widget
). Таким образом, данные компиляторы сообщают нам, что и Т
, и param
имеют один и тот же тип — const Widget*
. Компилятор Microsoft согласен:
Т = class Widget const *
param = class Widget const *
Три независимых компилятора дают одну и ту же информацию, что свидетельствует о том, что эта информация является точной. Но давайте посмотрим более внимательно. В шаблоне f
объявленным типом param является тип const Т&
. В таком случае не кажется ли вам странным, что и Т
, и param
имеют один и тот же тип? Если тип Т
, например, представляет собой int
, то типом param
должен быть const int&
— совершенно другой тип.
К сожалению, результат std::type_info::name
ненадежен. Например, в данном случае тип, который все три компилятора приписывают param
, является неверным. Кроме того, он по сути обязан быть неверным, так как спецификация std::type_info::name
разрешает, чтобы тип рассматривался как если бы он был передан в шаблонную функцию по значению. Как поясняется в разделе 1.1, это означает, что если тип является ссылкой, его “ссылочность” игнорируется, а если тип после удаления ссылочности оказывается const
(или volatile
), то соответствующие модификаторы также игнорируются. Вот почему информация о типе param
— который на самом деле представляет собой const Widget* const&
— выводится как const Widget*
. Сначала удаляется ссылочность, а затем у получившегося указателя удаляется константность.
Не менее печально, что информация о типе, выводимая редакторами IDE, также ненадежна — или как минимум ненадежно полезна. Для этого же примера мой редактор IDE сообщает о типе Т
как (я не придумываю!):
const
std::_Simple_types
std::allocator >::_Alloc>::value_type>::value_type *
Тот же редактор IDE показывает, что тип param следующий:
const std::_Simple_types<...>::value_type *const &
Это выглядит менее страшно, чем тип Т
, но троеточие в средине типа сбивает с толку, пока вы не поймете, что это редактор IDE попытался сказать “Я опускаю все, что является частью типа T”. Ваша среда разработки, быть может, работает лучше моей — если вы достаточно везучий.
Если вы склонны полагаться на библиотеки больше, чем на удачу, то будете рады узнать, что там, где std::type_info::name
и IDE могут ошибаться, библиотека Boost TypeIndex (часто именуемая как Boost.TypeIndex ) приведет к успеху. Эта библиотека не является частью стандарта С++, но точно так же частью стандарта не являются ни IDE, ни шаблоны наподобие рассмотренного выше TD. Кроме того, тот факт, что библиотеки Boost (доступные по адресу boost.org
) являются кроссплатформенными, с открытым исходным кодом и с лицензией, разработанной так, чтобы быть приемлемой даже для самых параноидальных юристов, означает, что код с применением библиотек Boost переносим практически так же хорошо, как и код, основанный на стандартной библиотеке.
Вот как наша функция f
может выдать точную информацию о типах с использованием Boost.TypeIndex:
#include
template
void f(const T& param) {
using std::cout;
using boost::typeindex::type_id_with_cvr;
Интервал:
Закладка: