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

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

, которые получают итератор “подсказки”, а у >std::forward_list имеется >emplace_after, соответствующий его >insert_after.

Что позволяет функциям размещения превзойти функции вставки, так это их более гибкий интерфейс. Функции вставки получают вставляемые объекты, в то время как функции размещения получают аргументы конструктора вставляемых объектов. Это отличие позволяет функциям размещения избегать создания и уничтожения временных объектов, которые могут требоваться функциям вставки.

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

>std::string queenOfDisco("Donna Summer");

оба приведенных далее вызова корректны, и оба приводят к одному и тому же результату:

>vs.push_back(queenOfDisco);    // Копирующее конструирование

>                               // queenOfDisco в конце vs

>vs.emplace_back(queenOfDisco); // То же самое

Таким образом, размещающие функции могут делать все то же самое, что и функции вставки. Иногда они делают это более эффективно и как минимум теоретически не должны делать менее эффективно. Так почему же мы не используем их все время?

Потому что теоретически разницы между теорией и практикой нет, а практически — есть. При текущих реализациях стандартной библиотеки имеются ситуации, когда, как и ожидается, размещение превосходит вставку, но — увы! — есть ситуации, когда вставка работает быстрее. Такие ситуации непросто охарактеризовать, поскольку они зависят от типов передаваемых аргументов, используемых контейнеров, местоположения вставки или размещения в контейнере, безопасности исключений конструкторов типов, содержащихся в контейнере, и для контейнеров, в которых запрещены дубликаты (т.e. >std::set, >std::map, >std::unordered_set, >std::unordered_map), от того, содержится ли уже в контейнере вставляемое значение. А потому следует пользоваться обычным советом по повышению производительности: для определения того, какой метод работает быстрее, надо сравнивать их реальную производительность в конкретных условиях.

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

• Добавляемое значение конструируется в контейнере, а не присваивается. Пример, с которого начат данный раздел (добавление >std::string со значением >"xyzzy" в >std::vector vs), демонстрирует значение, добавляемое в конец вектора >vs — в место, где пока что нет никакого объекта. Таким образом, новое значение должно быть сконструировано в >std::vector. Если мы пересмотрим пример так, что новая строка >std::string будет направляться в местоположение, уже занятое объектом, это будет совсем другая история:

>std::vector vs;     // Как и ранее

>…                                // Добавление элементов в vs

>vs.emplace(vs.begin(), "xyzzy"); // Добавление "xyzzy" в начало vs

При таком коде только редкие реализации будут конструировать добавляемый объект >std::string в памяти, занятой >vs[0]. Большинство реализаций используют перемещающее присваивание в указанное место. Но перемещающее присваивание требует наличия перемещаемого объекта, а это означает, что необходимо создание временного объекта. Поскольку основное преимущество размещения над вставкой заключается в том, что не создаются и не уничтожаются временные объекты, при добавлении значения в контейнер с помощью присваивания преимущества размещения исчезают.

Увы, выполняется ли добавление значения в контейнер путем конструирования или перемещения, в общем случае зависит от реализации. И вновь на помощь может прийти эвристика.

Контейнеры на основе узлов почти всегда используют для добавления новых значений конструирование, а большинство стандартных контейнеров являются именно таковыми. Исключениями являются >std::vector, >std::deque и >std::string. (Контейнер >std::array также не является таковым, но он не поддерживает ни вставку, ни размещение, поэтому упоминать о нем здесь нет смысла.) В контейнерах, не основанных на узлах, можно рассчитывать на использование функцией >emplace_back для размещения нового значения конструирования вместо присваивания; то же самое можно сказать и о функции >emplace_front контейнера >std::deque.

• Типы передаваемых аргументов отличаются от типа, хранящегося в контейнере. И вновь, преимущество размещения по сравнению со вставкой в общем случае связано с тем фактом, что его интерфейс не требует создания и уничтожения временного объекта при передаче аргументов типа, отличного от типа, хранящегося в контейнере. Когда в контейнер >container добавляется объект типа >T, нет причин ожидать, что размещение окажется быстрее вставки, поскольку для удовлетворения интерфейсу вставки не требуется создание временного объекта.


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

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


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

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


Рекомендуем почитать
Изучаем Java EE 7

Java Enterprise Edition (Java EE) остается одной из ведущих технологий и платформ на основе Java. Данная книга представляет собой логичное пошаговое руководство, в котором подробно описаны многие спецификации и эталонные реализации Java EE 7. Работа с ними продемонстрирована на практических примерах. В этом фундаментальном издании также используется новейшая версия инструмента GlassFish, предназначенного для развертывания и администрирования примеров кода. Книга написана ведущим специалистом по обработке запросов на спецификацию Java EE, членом наблюдательного совета организации Java Community Process (JCP)


Платформа J2Me

Эта книга научит вас, как разрабатывать программное обеспечение для платформы J2ME компании «Sun Microsystems». Эта книга придерживается стиля учебного пособия, это не справочное руководство.Цель — дать вам твердую основу в понятиях и техниках, которая даст вам возможность решиться на самостоятельную разработку качественных приложений.


Виртуальная библиотека Delphi

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


Обработка баз данных на Visual Basic.NET

Это практическое руководство разработчика программного обеспечения на Visual Basic .NET и ADO.NET, предназначенное для создания приложений баз данных на основе WinForms, Web-форм и Web-служб. В книге описываются практические способы решения задач доступа к данным, с которыми сталкиваются разработчики на Visual Basic .NET в своей повседневной деятельности. Книга начинается с основных сведений о создании баз данных, использовании языка структурированных запросов SQL и системы управления базами данных Microsoft SQL Server 2000.


Исчерпывающее руководство по написанию всплывающих подсказок

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


Программное обеспечение встроенных систем. Общие требования к разработке и документированию

Embedded system software. General requirements for development and documentationСтандарт подготовлен в развитие ГОСТ Р ИСО/МЭК 12207-99 «Информационная технология. Процессы жизненного цикла программных средств» с целью учета специфики разработки и документирования программного обеспечения встроенных систем реального времени.