Переместить конструкторы и `std:: array`
Согласно N3485 §23.3.2.2:
(...) неявный механизм перемещения и оператор назначения перемещения для массива требуют, чтобы T было MoveConstructible или MoveAssignable соответственно.
Итак, std::array
поддерживает перемещение семантики, если тип его элементов. Отлично!
Однако, что это значит? Я склонен представить этот тип как более безопасную версию массива, предоставляющую интерфейс, совместимый с STL, но если это правда, то как std::array
перемещать-строить свои элементы? Могу ли я сделать то же самое с обычным массивом?
Ответы
Ответ 1
Однако, что это значит?
Это означает, что если тип элемента является подвижным, то и тип массива.
std::array<movable, 42> move_from = {...};
std::array<movable, 42> move_to = std::move(move_from); // moves all the elements
Я склонен представить этот тип как более безопасную версию массива, предоставляющую интерфейс, совместимый с STL
Не совсем. Это оболочка для массива, предоставляющая ему ту же семантику, что и совокупный класс, включая возможность копирования и перемещения.
как std::array
перемещать-конструировать свои элементы?
Точно так же, как и любой другой агрегат. Его неявный move-constructor будет перемещать-строить все его элементы, включая элементы любых массивов-членов.
Могу ли я сделать то же самое с обычным массивом?
Только если вы завернете его в тип класса, как это делает std::array
.
Ответ 2
Перемещение a std::array
отличается от перемещения a std::vector
. При перемещении одного std::vector
в другое, он (иногда *) позволяет просто переназначить внутренние указатели и вообще не манипулировать элементами.
С std::array
это, конечно, невозможно - его элементы имеют автоматическую продолжительность хранения, они буквально содержатся внутри объекта. Тем не менее, каждый отдельный из них все еще может быть перемещен и что операции перемещения на std::array
делают **.
* Предполагая, что распределители совместимы и не запрещают эту операцию
** Это также то, что вы получаете с помощью std::vector
, когда буфер не может быть повторно использован целевым вектором.
Ответ 3
Конструктор перемещения по умолчанию для (неединичного) класса выполняет поэтапный ход. Перемещение элемента данных необработанного массива означает перемещение каждого из элементов массива, см. [Class.copy]/15.
Следовательно, вы можете перемещать необработанный массив, помещая его внутри класса:
struct wrap
{
std::string arr[25];
};
auto w = wrap();
auto m = std::move(w); // moves the 25 `std::string`s
Вы также можете вручную вызвать конструктор перемещения элементов, например:
std::string a[3] = { /*...*/ };
std::string b[3] = {std::move(a[0]), std::move(a[1]), std::move(a[2])};
Не указывается, если std::array
содержит необработанный массив. Однако он содержит элементы данных value_type
, так как он гарантированно является совокупностью. Эти элементы данных будут перемещены, как описано выше, при вызове конструктора перемещения.
Если члены данных из std::array
не являются MoveConstructible, то создается экземпляр его конструктора перемещения.
Ответ 4
Вы можете сделать это, используя "размещение new
". Вы найдете много вопросов по размещению новых, уже ответивших на многие другие подробности.
Этот выглядит так, как будто он имеет полный пример: