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

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

, вероятно, не настолько описательно, как мы надеялись: >RvalueRefToT представляет собой >typedef для lvalue-ссылки, когда >Widget инстанцируется типом lvalue-ссылки.

Последним контекстом, в котором имеет место сворачивание ссылок, является использование >decltype. Если во время анализа типа, включающего >decltype, возникает ссылка на ссылку, она устраняется сворачиванием ссылок. (Информацию о >decltype вы найдете в разделе 1.3.)

Следует запомнить

• Сворачивание ссылок встречается в четырех контекстах: инстанцирование шаблона, генерация типа >auto, создание и применение >typedef и объявлений псевдонимов, и >decltype.

• Когда компиляторы генерируют ссылку на ссылку в контексте сворачивания ссылок, результатом становится единственная ссылка. Если любая из исходных ссылок является lvalue-ссылкой, результатом будет lvalue-ссылка; в противном случае это будет rvalue-ссылка.

• Универсальные ссылки представляют собой rvalue-ссылки в контекстах, в которых вывод типов отличает lvalue от rvalue и происходит сворачивание ссылок.

5.7. Считайте, что перемещающие операции отсутствуют, дороги или не используются

Семантика перемещения, пожалуй, самая главная возможность С++11. Вам наверняка приходилось слышать, что “перемещение контейнеров теперь такое же дешевое, как и копирование указателей” или что “копирование временных объектов теперь настолько эффективно, что избегать его равносильно преждевременной оптимизации”. Понять такие настроения легко. Семантика перемещения действительно является очень важной возможностью. Она не просто позволяет компиляторам заменять дорогостоящие операции копирования относительно дешевыми перемещениями, но и требует от них этого (при выполнении надлежащих условий). Возьмите ваш код С++98, перекомпилируйте его с помощью компилятора и стандартной библиотеки С++11 и — о чудо! — ваша программа заработает быстрее.

Семантика перемещения действительно в состоянии осуществить все это — и потому достойна легенды. Однако легенды, как правило, — это результат преувеличения. Цель данного раздела — спустить вас с небес на землю.

Начнем с наблюдения, что многие типы не поддерживают семантику перемещения. Вся стандартная библиотека С++98 была переработана с целью добавления операций перемещения для типов, в которых перемещение могло быть реализовано быстрее копирования, и реализации компонентов библиотеки были пересмотрены с целью использования преимуществ новых операций; однако есть вероятность, что вы работаете с кодом, который не был полностью переделан под C++11. Для типов в ваших приложениях (или в используемых вами библиотеках), в которые не были внесены изменения для С++11, мало пользы от наличия поддержки перемещения компилятором. Да, С++ 11 готов генерировать перемещающие операции для классов, в которых они отсутствуют, но это происходит только для классов, в которых не объявлены копирующие операции, перемещающие операции или деструкторы (см. раздел 3.11). Члены-данные базовых классов типов, в которых перемещения отключены (например, путем удаления перемещающих операций; см. раздел 3.5) также подавляют перемещающие операции, генерируемые компиляторами. Для типов без явной поддержки перемещения и типов, которые не могут претендовать на перемещающие операции, генерируемые компилятором, нет оснований ожидать что С++11 обеспечит повышение производительности по сравнению с С++98.

Даже типы с явной поддержкой перемещений не могут обеспечить все, на что вы надеетесь. Например, все контейнеры стандартной библиотеки С++11 поддерживают перемещение, но было бы ошибкой считать, что перемещение является дешевой операцией для всех контейнеров. Для одних контейнеров это связано с тем, что нет никакого действительно дешевого способа перемещения их содержимого. Для других — с тем, что действительно дешевые перемещающие операции предлагаются контейнерами с оговорками, которым не удовлетворяют конкретные элементы контейнера.

Рассмотрим новый контейнер C++11 — >std::array. Контейнер >std::array, по сути, представляет собой встроенный массив с STL-интерфейсом. Он фундаментально отличается от других стандартных контейнеров, которые хранят свое содержимое в динамической памяти. Объекты таких типов контейнеров концептуально содержат (в качестве членов-данных) только указатель на динамическую память, хранящую содержимое контейнера. (Действительность более сложна, но для наших целей эти отличия не играют роли.) Наличие такого указателя позволяет перемещать содержимое всего контейнера на константное время: просто копируя указатель на содержимое контейнера из исходного контейнера в целевой и делая указатель исходного контейнера нулевым:

>std::vector vw1;

>// Размещение данных в vw1

>// Перемещение vw1 в vw2. Выполняется

>// за константное время, изменяя

>// только указатели в vw1 и vw2

>auto vw2 = std::move(vw1);

Объекты >std::array не содержат такого указателя, поскольку данные, содержащиеся в >std::array, хранятся непосредственно в объекте >std::array:

>std::array aw1;

>// Размещение данных в vw1

>// Перемещение vw1 в vw2. Выполняется

>// за линейное время. Все элементы


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

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


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

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


Рекомендуем почитать
Pro Git

Разработчику часто требуется много сторонних инструментов, чтобы создавать и поддерживать проект. Система Git — один из таких инструментов и используется для контроля промежуточных версий вашего приложения, позволяя вам исправлять ошибки, откатывать к старой версии, разрабатывать проект в команде и сливать его потом. В книге вы узнаете об основах работы с Git: установка, ключевые команды, gitHub и многое другое.В книге рассматриваются следующие темы:основы Git;ветвление в Git;Git на сервере;распределённый Git;GitHub;инструменты Git;настройка Git;Git и другие системы контроля версий.


Java 7

Рассмотрено все необходимое для разработки, компиляции, отладки и запуска приложений Java. Изложены практические приемы использования как традиционных, так и новейших конструкций объектно-ориентированного языка Java, графической библиотеки классов Swing, расширенной библиотеки Java 2D, работа со звуком, печать, способы русификации программ. Приведено полное описание нововведений Java SE 7: двоичная запись чисел, строковые варианты разветвлений, "ромбовидный оператор", NIO2, новые средства многопоточности и др.


MFC и OpenGL

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


Симуляция частичной специализации

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


Обработка событий в С++

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


Питон — модули, пакеты, классы, экземпляры

Python - объектно-ориентированный язык сверхвысокого уровня. Python, в отличии от Java, не требует исключительно объектной ориентированности, но классы в Python так просто изучить и так удобно использовать, что даже новые и неискушенные пользователи быстро переходят на ОО-подход.