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

Тут можно читать онлайн Скотт Мейерс - Эффективный и современный С++. 42 рекомендации по использованию С++11 и С++14 - бесплатно полную версию книги (целиком) без сокращений. Жанр: comp-programming, издательство Вильямс, год 2016. Здесь Вы можете читать полную версию (весь текст) онлайн без регистрации и SMS на сайте лучшей интернет библиотеки ЛибКинг или прочесть краткое содержание (суть), предисловие и аннотацию. Так же сможете купить и скачать торрент в электронном формате fb2, найти и слушать аудиокнигу на русском языке или узнать сколько частей в серии и всего страниц в публикации. Читателям доступно смотреть обложку, картинки, описание и отзывы (комментарии) о произведении.
  • Название:
    Эффективный и современный С++. 42 рекомендации по использованию С++11 и С++14
  • Автор:
  • Жанр:
  • Издательство:
    Вильямс
  • Год:
    2016
  • Город:
    Москва
  • ISBN:
    978-5-8459-2000-3
  • Рейтинг:
    3/5. Голосов: 11
  • Избранное:
    Добавить в избранное
  • Отзывы:
  • Ваша оценка:
    • 60
    • 1
    • 2
    • 3
    • 4
    • 5

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

Эффективный и современный С++. 42 рекомендации по использованию С++11 и С++14 - описание и краткое содержание, автор Скотт Мейерс, читайте бесплатно онлайн на сайте электронной библиотеки LibKing.Ru
Эффективный и современный С++
В книге рассматриваются следующие темы. Освоение С++11 и С++14 — это больше, чем просто ознакомление с вводимыми этими стандартами возможностями (например, объявлениями типов
, семантикой перемещения, лямбда-выражениями или поддержкой многопоточности). Вопрос в том, как использовать их эффективно, чтобы создаваемые программы были корректны, эффективны и переносимы, а также чтобы их легко можно было сопровождать. Именно этим вопросам и посвящена данная книга, описывающая создание по-настоящему хорошего программного обеспечения с использованием C++11 и С++14 — т.е. с использованием современного С++.
■ Преимущества и недостатки инициализации с помощью фигурных скобок, спецификации
, прямой передачи и функций
интеллектуальных указателей
■ Связь между
,
, rvalue-ссылками и универсальными ссылками
■ Методы написания понятных, корректных,
лямбда-выражений
■ Чем
отличается от
, как они используются и как соотносятся с API параллельных вычислений С++
■ Какие из лучших методов “старого” программирования на С++ (т.е. С++98) должны быть пересмотрены при работе с современным С++
Более чем 20 лет книги
серии
являются критерием уровня книг по программированию на С++. Понятное пояснение сложного технического материала принесло ему всемирную известность. Он всегда самый желанный гость на международных конференциях, а его услуги консультанта широко востребованы во всем мире.
Скотт Мейерс Эффективный и современный С++, После изучения основ С++ я перешел к изучению того, как применять С++ в промышленном программировании, с помощью серии книг Скотта Мейерса Эффективный С++. Эффективный и современный С++ — наиболее важная из книг серии, предлагающая ключевые рекомендации, стили и идиомы, позволяющие эффективно использовать современный С++. Вы еще не купили эту книгу? Сделайте это прямо сейчас. Герб Саттер,
глава Комитета ISO по стандартизации С++, специалист в области архитектуры программного обеспечения на С++ в Microsoft

Эффективный и современный С++. 42 рекомендации по использованию С++11 и С++14 - читать онлайн бесплатно полную версию (весь текст целиком)

Эффективный и современный С++. 42 рекомендации по использованию С++11 и С++14 - читать книгу онлайн бесплатно, автор Скотт Мейерс
Тёмная тема
Сбросить

Интервал:

Закладка:

Сделать

std::multiset names; // Глобальная структура данных

void logAndAdd(const std::string& name) {

auto now = // Получение текущего времени

std::chrono::system_clock::now();

log(now, "logAndAdd"); // Создание журнальной записи

names.emplace(name); // Добавление nаmе в глобальную

} // структуру данных; emplace

// см. в разделе 8.2

Этот код не является неразумным, но он не такой эффективный, каким мог бы быть. Рассмотрим три потенциальных вызова:

std::string petName("Darla");

logAndAdd( petName); // lvalue типа std::string

logAndAdd( std::string("Persephone")); // rvalue типа std::string

logAndAdd( "Patty Dog"); // Строковый литерал

В первом вызове параметр паше функции logAndAddсвязывается с переменной petName. Внутри logAndAddпараметр name в конечном итоге передается в вызов names.emplace. Поскольку nameявляется lvalue, он копируется в names. Избежать этого копирования невозможно, так как lvalue(petName)передается в функцию logAndAdd.

Во втором вызове параметр nameсвязывается с rvalue (временный объект std::string, явно созданный из строки "Persephone"). Параметр nameсам по себе является lvalue, так что он копируется в names, но мы отдаем себе отчет, что, в принципе, это значение может быть перемещено в names. В этом вызове мы платим за копирование, но мы должны быть способны сделать то же с помощью перемещения.

В третьем вызове параметр name опять связывается с rvalue, но в этот раз со временным объектом std::string, который неявно создается из "Patty Dog". Как и во втором вызове, nameкопируется в names, но в этот раз аргумент, изначально переданный в logAndAdd, был строковым литералом. Если бы строковый литерал непосредственно передавался в emplace, в создании временного объекта std::stringне было бы необходимости вообще. Вместо этого функция emplaceиспользовала бы строковый литерал для создания объекта std::stringнепосредственно в std::multiset. Таким образом, в этом третьем вызове мы платим за копирование std::string, при том что нет причин платить даже за перемещение, не говоря уже о копировании.

Неэффективность второго и третьего вызовов logAndAddможно устранить, переписав эту функцию так, чтобы она принимала универсальную ссылку (см. раздел 5.2) и, согласно разделу 5.3, передавала ее с помощью std::forwardфункции emplace. Результат говорит сам за себя:

template

void logAndAdd(T&& name) {

auto now = std::chrono::system_clock::now();

log(now, "logAndAdd");

names.emplace( std::forward(name));

}

std::string petName("Darla"); // Как и ранее

logAndAdd( petName); // Как и ранее, копирова-

// ние lvalue в multiset

logAndAdd( std::string("Persephone")); // Перемещение rvalue

// вместо копирования

logAndAdd( "Patty Dog"); // Создание std::string

// в multiset вместо

// копирования временного

// std::string

Ура, получена оптимальная эффективность!

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

std::string nameFromIdx(int idx); // Возвращает имя,

// соответствующее idx

void logAndAdd( int idx) // Новая перегрузка

{

auto now = std::chrono::system_clock::now();

log(now, "logAndAdd");

names.emplace( nameFromIdx(idx));

}

Разрешение перегрузки работает, как и следовало ожидать:

std::string petName("Darla"); // Как и ранее

logAndAdd(petName); // Как и ранее, эти вызовы

logAndAdd(std::string("Persephone")); // приводят к использова-

logAndAdd("Patty Dog"); // нию перегрузки для T&&

logAndAdd(22); // Вызов int-перегрузки

На самом деле разрешение работает, как ожидается, только если вы не ожидаете слишком многого. Предположим, клиент имеет переменную типа short, хранящую индекс, и передает ее функции logAndAdd:

short nameIdx;

… // Дает значение переменной nameIdx

logAndAdd(nameIdx); // Ошибка!

Комментарий в последней строке, может быть, не слишком понятен, так что позвольте мне пояснить, что же здесь произошло.

Имеется две перегрузки logAndAdd. Одна из них, принимающая универсальную ссылку, может вывести тип Tкак short, тем самым приводя к точному соответствию. Перегрузка с параметром intможет соответствовать аргументу shortтолько с повышением. Согласно обычным правилам разрешения перегрузки точное соответствие побеждает соответствие с повышением, так что вызывается перегрузка для универсальной ссылки.

В этой перегрузке параметр nameсвязывается с переданным значением типа short. Таким образом, nameпередается с помощью std::forwardфункции-члену emplaceобъекта names(std::multiset), которая, в свою очередь, послушно передает его конструктору std::string. Но конструктора std::string, который принимал бы значение short, не существует, так что вызов конструктора std::stringв вызове multiset::emplaceв вызове logAndAddнеудачен. Все дело в том, что перегрузка для универсальной ссылки точнее соответствует аргументу типа short, чем перегрузка для int.

Функции, принимающие универсальные ссылки, оказываются самыми жадными в С++. Они в состоянии выполнить инстанцирование с точным соответствием практически для любого типа аргумента (несколько видов аргументов, для которых это не так, описаны в разделе 5.8). Именно поэтому сочетание перегрузки и универсальной ссылки почти всегда является плохой идеей: перегрузка для универсальных ссылок годится для гораздо большего количества типов аргументов, чем обычно ожидает разработчик перегрузок.

Простой способ свалиться в эту яму — написать конструктор с прямой передачей. Небольшое изменение функции logAndAddдемонстрирует эту проблему. Вместо написания свободной функции, которая принимает либо std::string, либо индекс, который можно использовать для поиска std::string, представим себе класс Personс конструкторами, которые выполняют те же действия:

class Person {

public:

template

explicit Person(T&& n) // Конструктор с прямой передачей

: name(std::forward(n)){} // инициализирует члены-данные

explicit Person(int idx) // Конструктор с параметром int

: name(nameFromIdx(idx)) {}

private:

std::string name;

};

Как и в случае с logAndAdd, передача целочисленного типа, отличного от int(например, std::size_t, short, longи т.п.), будет вызывать перегрузку конструктора для универсальной ссылки вместо перегрузки для int, и это будет вести к ошибкам компиляции. Однако проблема гораздо хуже, поскольку в Person имеется больше перегрузок, чем видит глаз. В разделе 3.11 поясняется, что при соответствующих условиях С++ будет генерировать как копирующие, так и перемещающие конструкторы, и это так и будет, даже если класс содержит шаблонный конструктор, который при инстанцировании в состоянии дать сигнатуру копирующего или перемещающего конструктора. Если таким образом генерируются копирующий и перемещающий конструкторы для Person, класс Personбудет выглядеть, по сути, следующим образом:

Читать дальше
Тёмная тема
Сбросить

Интервал:

Закладка:

Сделать


Скотт Мейерс читать все книги автора по порядку

Скотт Мейерс - все книги автора в одном месте читать по порядку полные версии на сайте онлайн библиотеки LibKing.




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


Отзывы читателей о книге Эффективный и современный С++. 42 рекомендации по использованию С++11 и С++14, автор: Скотт Мейерс. Читайте комментарии и мнения людей о произведении.


Понравилась книга? Поделитесь впечатлениями - оставьте Ваш отзыв или расскажите друзьям

Напишите свой комментарий
x