Вставка в вектор только для перемещения - PullRequest
0 голосов
/ 17 февраля 2019

У меня есть std::vector<std::unique_ptr<T>>.Я бы хотел insert несколько nullptr с в середине этого вектора.Я попытался vec.insert(first, size, nullptr), но это, очевидно, не работает, потому что nullptr нужно скопировать.Я мог бы неоднократно называть единственную версию insert, но мне было интересно, есть ли более эффективный способ.

Ответы [ 2 ]

0 голосов
/ 17 февраля 2019

Вы можете собрать свой собственный итератор, который создает экземпляры по умолчанию при разыменовании.Это значения, которые позволяют создавать в векторе только для перемещения типы.Используйте подсчет экземпляров такого итератора для вызова std::vector::insert.Вот пример, который, вероятно, не соответствует стандарту, но работает.

template <class T>
class DefaultCtorInputIt {
   public:
      DefaultCtorInputIt(size_t n) : n(n) {}

      using value_type = T;
      using reference = T;
      using pointer = T;
      using iterator_category = std::input_iterator_tag ;
      using difference_type = int;
      using Self = DefaultCtorInputIt; // save typing (below)

      value_type operator *() { return T(); }
      Self& operator ++() { ++n; return *this; }

      friend bool operator == (const Self& lhs, const Self& rhs) {
         return lhs.n == rhs.n;
      }

      friend bool operator != (const Self& lhs, const Self& rhs) {
         return !(lhs == rhs);
      }

   private:
      size_t n;
};

Таким образом, вы можете

std::vector<std::unique_ptr<int>> v;

 // Fill v with some values...

using NullUPtr =DefaultCtorInputIt<std::unique_ptr<int>>; // save typing

// Insert 10 default constructed instances at desired position:
v.insert(v.begin() + 42, NullUPtr(0), NullUPtr(10));

Обратите внимание, что для того, чтобы это было максимально эффективно, вы, вероятно, должны сделатьубедитесь, что приведенный выше итератор квалифицируется как итератор с произвольным доступом, так что размер диапазона [NullUPtr(0), NullUPtr(10)) может быть вычислен с O (1) заранее, чтобы выделить память только один раз.При создании собственного типа итератора также стоит взглянуть на Повысить фасад итератора .

0 голосов
/ 17 февраля 2019

«Эффективный» - это то, что нужно измерить.Но если вы хотите сдвинуть элементы за один раз, вместо того, чтобы постоянно перемещать их на один пункт вправо, вы можете сделать это с помощью std::rotate.Вот как

vec.resize(vec.size() + size); // Add the "null" pointers to the end.
// Obtain valid first after resize
std::rotate(first, vec.end() - size, vec.end());

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

Кроме того, поскольку вы пометили C ++ 17, вы также можете передать стандартному алгоритму политику выполнения и, надеюсь, получить некоторый параллелизм для загрузки.

...