Я рекомендую изучить заголовок <vector>
файла libc++. Вам придется иметь дело со всеми неприятными символами подчеркивания, которые должны использовать разработчики std::lib. Но у libc++ есть реализация, совместимая с C++11, для проверки.
оператор присваивания перемещения
Оператор назначения перемещения контейнера должен иметь дело с тремя отдельными возможностями:
propagate_on_container_move_assignment
верно.
propagate_on_container_move_assignment
ложно, и аллокаторы из левого и правого сравниваются равными.
propagate_on_container_move_assignment
ложно, а распределители из левого и правого сравниваются неравномерно.
Когда это возможно, решение между этими тремя случаями должно приниматься во время компиляции, а не во время выполнения. В частности, следует выбирать между наборами {1} и {2, 3} во время компиляции, поскольку propagate_on_container_move_assignment
является константой времени компиляции. Ветвление во время компиляции для константы времени компиляции часто выполняется с помощью диспетчеризации тегов, а не с помощью оператора if, как вы шоу.
Ни в одном из этих случаев не следует использовать select_on_container_copy_construction
. Эта функция предназначена только для конструктора копирования контейнера.
В случае 1 левая сторона должна сначала использовать аллокатор левой руки, чтобы освободить всю выделенную память. Это необходимо сделать в первую очередь, потому что аллокатор rhs не сможет освободить эту память позже. Затем левый распределитель назначается перемещением из правого распределителя (точно так же, как любое другое назначение перемещения). Затем право собственности на память передается из правого контейнера в левый. Если дизайн вашего контейнера таков, что контейнер rhs нельзя оставить в состоянии без ресурсов (плохой дизайн imho), то новый ресурс может быть выделен распределителем, перемещенным из rhs, для контейнера rhs.
Когда propagate_on_container_move_assignment
равно false, вы должны выбирать между случаями 2 и 3 во время выполнения, поскольку сравнение распределителя является операцией времени выполнения.
В случае 2 вы можете сделать то же самое, что и в случае 1, за исключением того, что за исключением не перемещайте распределители. Просто пропустите этот шаг.
В случае 3 вы не можете передать право собственности на какую-либо память из контейнера rhs в контейнер lhs. Единственное, что вы можете сделать, это как бы:
assign(make_move_iterator(rhs.begin()), make_move_iterator(rhs.end()));
Обратите внимание, что в случае 1, поскольку алгоритм был выбран во время компиляции, value_type
контейнера не обязательно должно быть MoveAssignable
или MoveInsertable
(MoveConstructible
) для перемещения-назначения контейнера. Но в случае 2 value_type
s делать должны быть MoveAssignable
и MoveInsertable
(MoveConstructible
), даже если они никогда не бывают таковыми, потому что вы выбираете между 2 и 3 во время выполнения. И 3 нужны эти операции на value_type
для выполнения assign
.
Оператор присваивания перемещения — самый сложный специальный член для реализации контейнеров. Остальные намного проще:
конструктор перемещения
Конструктор перемещения просто перемещает аллокатор и крадет ресурсы из rhs.
конструктор копирования
Конструктор копирования получает свой распределитель от select_on_container_copy_construction(rhs.m_alloc)
, а затем использует его для выделения ресурсов для копии.
оператор присваивания копии
Оператор присваивания копии должен сначала проверить, истинно ли propagate_on_container_copy_assignment
. Если это так, и если левый и правый аллокаторы сравниваются неравномерно, то левый должен сначала освободить всю память, потому что он не сможет сделать это позже, после того, как аллокаторы будут назначены для копирования. Далее, если propagate_on_container_copy_assignment
, скопируйте назначение распределителей, иначе не делайте этого. Затем скопируйте элементы:
assign(rhs.begin(), rhs.end());
person
Howard Hinnant
schedule
14.12.2014