Новое размещение с конструктором перемещения против назначения перемещения в folly small_vector

#c #vector #c 17 #folly

#c #вектор #c 17 #folly

Вопрос:

Исследуя идеи для векторного контейнера constexpr, я столкнулся с контейнером folly small_vector. Я читал реализацию и был смущен этой частью moveObjectsRightAndCreate :

     for (; in != first amp;amp; out > lastConstructed;) {
      // Out must be decremented before an exception can be thrown so that
      // the rollback guard knows where to start.
      --out;
      new (out) T(std::move(*(--in)));
    }
    for (; in != first;) {
      --out;
      *out = std::move(*(--in));
    }
    for (; out > lastConstructed;) {
      --out;
      new (out) T(create());
    }
    for (; out != first;) {
      --out;
      *out = create();
    }
 

Насколько я понимаю, для частей массива, где память была неинициализирована, они используют размещение нового с std::move помощью . Для частей массива, из которых ранее были перемещены объекты, они используют назначение перемещения.

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

Комментарии:

1. Вы спрашиваете, почему он просто не создает новый объект поверх той же памяти, где все еще существует старый объект?

2. @JosephSible-Восстановление в принципе, да. В этом случае старый объект уже должен был быть перемещен из-за предыдущих вызовов размещения new. Более того, поскольку мы вручную управляем памятью, я чувствую, что мне не нужно беспокоиться о вызове деструктора для неинициализированной памяти или какого-либо недопустимого объекта, но я, вероятно, что-то недопонимаю.

3. Подсказка: что произойдет, если у вас есть класс, который (1) управляет ресурсом и (2) может быть скопирован, но не перемещаем (возможно, потому, что он был написан до того, как существовали конструкторы перемещения)?

4. @JosephSible-Переустановите MONICA Ах, хорошо, я думаю, я понимаю, к чему вы клоните. Например, если класс реализует совместное владение ресурсом, то можно ожидать, что конструктор копирования добавит ссылку на ресурс, но назначение копирования должно удалить старую ссылку перед добавлением новой. Я предполагаю, что это недопустимо так же, как выделение памяти и попытка копирования недопустимы.

Ответ №1:

Почему бы не использовать размещение нового для обоих случаев

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

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

Является ли фактическая причина одной из них или чем-то другим, может ответить только автор контейнера.

Почему бы не использовать назначение перемещения для обоих случаев?

Поскольку поведение назначения перемещения нетривиального типа в неинициализированной памяти не определено.