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

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

>// aw1 перемещаются в aw2

>auto aw2 = std::move(aw1);

Обратите внимание, что все элементы из >aw1перемещаются в >aw2. В предположении, что >Widget представляет собой тип, операция перемещения которого выполняется быстрее операции копирования, перемещение >std::array элементов >Widget будет более быстрым, чем копирование того же >std::array. Поэтому >std::array предлагает поддержку перемещения. И копирование, и перемещение >std::array имеют линейное время работы, поскольку должен быть скопирован или перемещен каждый элемент контейнера. Это весьма далеко от утверждения “перемещение контейнеров теперь такое же дешевое, как и копирование указателей”, которое иногда приходится слышать.

С другой стороны, >std::string предлагает перемещение за константное время и копирование — за линейное. Создается впечатление, что в этом случае перемещение быстрее копирования, но это может и не быть так. Многие реализации строк используют оптимизацию малых строк (small string optimization — SSO). При использовании SSO “малые” строки (например, размером не более 15 символов) хранятся в буфере в самом объекте >std::string; выделение динамической памяти не используется. Перемещение малых строк при использовании реализации на основе SSO не быстрее копирования, поскольку трюк с копированием только указателя на данные, который в общем случае обеспечивает повышение эффективности, в данном случае не применим.

Мотивацией применения SSO является статистика, указывающая, что короткие строки являются нормой для многих приложений. С помощью внутреннего буфера для хранения содержимого таких строк устраняется необходимость динамического выделения памяти для них, и это, как правило, дает выигрыш в эффективности. Следствием этого выигрыша является то, что перемещение оказывается не быстрее копирования… Хотя для любителей наполовину полного стакана[18] можно сказать, что для таких строк копирование не медленнее, чем перемещение.

Даже для типов, поддерживающих быстрые операции перемещения, некоторые кажущиеся очевидными ситуации могут завершиться созданием копий. В разделе 3.8 поясняется, что некоторые контейнерные операции в стандартной библиотеке предполагают строгие гарантии безопасности исключений и что для гарантии того, что старый код С++98, зависящий от этой гарантии, не станет неработоспособным при переходе на С++ 11, операции копирования могут быть заменены операциями перемещения, только если известно, что последние не генерируют исключений. В результате, даже если тип предоставляет перемещающие операции, более эффективные по сравнению с соответствующими копирующими операциями, и даже если в определенной точке кода перемещающая операция целесообразна (например, исходный объект представляет собой rvalue), компиляторы могут быть вынуждены по-прежнему вызывать копирующие операции, поскольку соответствующая перемещающая операция не объявлена как >noexcept.

Таким образом, имеется ряд сценариев, в которых семантика перемещения С++11 непригодна.

• Отсутствие перемещающих операций. Объект, из которого выполняется перемещение, не предоставляет перемещающих операций. Запрос на перемещение, таким образом, превращается в запрос на копирование.

• Перемещение не быстрее. Объект, из которого выполняется перемещение, имеет перемещающие операции, которые не быстрее копирующих.

• Перемещение неприменимо. Контекст, в котором должно иметь место перемещение, требует операцию, не генерирующую исключения, но операция перемещения не объявлена как >noexcept.

Стоит упомянуть также еще один сценарий, когда семантика перемещения не приводит к повышению эффективности.

• Исходный объект является lvalue. За очень малыми исключениями (см., например, раздел 5.3) только rvalue могут использоваться в качестве источника перемещающей операции.

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

Однако зачастую вам известно, какие типы использует ваш код, и вы можете положиться на неизменность их характеристик (например, на поддержку ими недорогих перемещающих операций). В этом случае вам не надо делать такие грустные предположения. Вы просто изучаете детали поддержки операций перемещения, используемых вашими типами. Если эти типы предоставляют недорогие операции перемещения и если вы используете объекты в контекстах, в которых эти операции будут вызываться, можете безопасно положиться на семантику перемещений при замене копирующих операций их менее дорогими перемещающими аналогами.

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

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

• В коде с известными типами или поддержкой семантики перемещения нет необходимости в таких предположениях.


Еще от автора Скотт Мейерс
Эффективное использование 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 так просто изучить и так удобно использовать, что даже новые и неискушенные пользователи быстро переходят на ОО-подход.