Цикл for перебирает существующие элементы и создает соответствующие элементы в новом пространстве. Указатель dest используется для указания на область памяти, в которой создается новая строка, а указатель elem — для указания на элемент в оригинальном массиве. Для перемещения указателей dest и elem на следующий элемент этих двух массивов используем постфиксный инкремент.
Второй аргумент в вызове функции construct() (т.е. аргумент, определяющий используемый конструктор (см. раздел 12.2.2)) является значением, возвращенным функцией move(). Вызов функции move() возвращает результат, заставляющий функцию construct() использовать конструктор перемещения класса string. Поскольку используется конструктор перемещения, управляемая память строки не будет скопирована. Вместо этого каждая создаваемая строка получит в собственность область памяти из строки, на которую указывает указатель elem.
После перемещения элементов происходит вызов функции free() для удаления прежних элементов и освобождения памяти, которую данный вектор StrVec использовал перед вызовом функции reallocate(). Сами строки больше не управляют памятью, в которой они располагались; ответственность за их данные была передана элементам нового вектора StrVec. Нам неизвестно содержимое строк в памяти прежнего вектора StrVec, но нам гарантирована безопасность запуска деструктора класса string для этих объектов.
Остается только обновить указатели адресами вновь созданного и инициализированного массива. Указатели first_free и cap обозначат элемент следующий после последнего созданного и следующий после последнего зарезервированного соответственно.
Упражнение 13.39. Напишите собственную версию класса StrVec, включая функции reserve(), capacity() (см. раздел 9.4) и resize() (см. раздел 9.3.5).
Упражнение 13.40. Добавьте в класс StrVec конструктор, получающий аргумент типа initializer_list.
Упражнение 13.41. Почему в вызове функции construct() в функции push_back() был использован постфиксный инкремент? Что случилось бы при использовании префиксного инкремента?
Упражнение 13.42. Проверьте свой класс StrVec, использовав его в классах TextQuery и QueryResult (см. раздел 12.3) вместо вектора vector.
Упражнение 13.43. Перепишите функцию-член free() так, чтобы для удаления элементов вместо цикла for использовалась функция for_each() и лямбда-выражение (см. раздел 10.3.2). Какую реализацию вы предпочитаете и почему?
Упражнение 13.44. Напишите класс по имени String, являющийся упрощенной версией библиотечного класса string. У вашего класса должен быть по крайней мере стандартный конструктор и конструктор, получающий указатель на строку в стиле С. Примените для резервирования используемой классом String памяти класс allocator.
Одной из главных особенностей нового стандарта является способность перемещать объект, а не копировать. Как упоминалось в разделе 13.1.1, копирование осуществляется при многих обстоятельствах. При некоторых из них объект разрушается немедленно после копирования. В этих случаях перемещение объекта вместо копирования способно обеспечить существенное увеличение производительности.
Как было продемонстрировано только что, наш класс StrVec — хороший пример лишнего копирования. Во время пересоздания нет никакой необходимости в копировании элементов из старой памяти в новую, лучше перемещение. Вторая причина предпочесть перемещение копированию — это такие классы как unique_ptr и классы ввода-вывода. У этих классов есть ресурс (такой как указатель или буфер ввода-вывода), который не допускает совместного использования. Следовательно, объекты этих типов не могут быть скопированы, но могут быть перемещены.
В прежних версиях языка не было непосредственного способа перемещения объекта. Копию приходилось делать, даже если в этом не было никакой потребности. Когда объекты велики или когда они требуют резервирования памяти (например, строки), бесполезное копирование может обойтись очень дорого. Точно так же в предыдущих версиях библиотеки классы хранимых в контейнере объектов должны были допускать копирование. По новому стандарту в контейнерах можно хранить объекты типов, которые не допускают копирования, но могут быть перемещены.
string и shared_ptr поддерживают как перемещение, так и копирование. Классы ввода-вывода и класс unique_ptr допускают перемещение, но не копирование.