我有一个std::vector<std::unique_ptr<T>>
。我想insert
一些nullptr
s进入这个向量的中间。我尝试了vec.insert(first, size, nullptr)
,但这显然不起作用,因为需要复制nullptr
。我可以反复调用insert
的单数版本,但我想知道是否有更有效的方法。
“高效”是需要衡量的。但是如果你想要一次性移动元素而不是不断地向右移动一个项目,你可以用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,您还可以将标准算法传递给执行策略,并希望获得一些并行性来启动。
您可以将自己的迭代器放在一起,在取消引用时创建默认实例。这些是prvalues,它允许在向量中构造仅移动类型。使用这种迭代器的计数实例来调用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));
请注意,为了使其尽可能高效,您应该确保上述迭代器符合随机访问迭代器的要求,这样可以使用O(1)预先计算范围[NullUPtr(0), NullUPtr(10))
的大小,以仅分配一次内存。当手工制作你自己的迭代器类型时,也值得一看Boost iterator facade。