我见过一些特殊情况,其中std::rotate
可以使用,或者与其中一种搜索算法结合使用,但一般情况下:当一个人拥有N个项目的向量并希望编写如下函数时:
void move( int from, int count, int to, std::vector<int>& numbers );
我一直在考虑创建一个新的向量+ std::copy
或插入/擦除的组合,但我不能说我最终得到了一些漂亮而优雅的解决方案。
答案 0 :(得分:10)
在得出任何结论之前,总是很重要。 vector
数据存储器的连续性可以提供基于节点的容器所没有的重要缓存优势。所以,也许你可以尝试直接的方法:
void move_range(size_t start, size_t length, size_t dst, std::vector<T> & v)
{
const size_t final_dst = dst > start ? dst - length : dst;
std::vector<T> tmp(v.begin() + start, v.begin() + start + length);
v.erase(v.begin() + start, v.begin() + start + length);
v.insert(v.begin() + final_dst, tmp.begin(), tmp.end());
}
在C ++ 11中,您将第一行和第三行中的迭代器包装到std::make_move_iterator
中。
(要求是dst
不在[start, start + length)
之内,否则问题的定义不明确。)
答案 1 :(得分:8)
根据矢量的大小和所涉及的范围,这可能比执行复制/删除/插入更便宜。
template <typename T>
void move_range(size_t start, size_t length, size_t dst, std::vector<T> & v)
{
typename std::vector<T>::iterator first, middle, last;
if (start < dst)
{
first = v.begin() + start;
middle = first + length;
last = v.begin() + dst;
}
else
{
first = v.begin() + dst;
middle = v.begin() + start;
last = middle + length;
}
std::rotate(first, middle, last);
}
(这假设范围有效且不重叠。)
答案 2 :(得分:2)
Pre-C ++ 11(尽管以下内容仍然有效),您可以为包含特殊/过载std::swap
的类型获得更有效的“移动”。要利用这一点,您需要执行类似
std::vector<Foo> new_vec;
Foo tmp;
for (/* each Foo&f in old_vec, first section */) {
swap (f, tmp);
new_vec .push_back (tmp);
}
for (/* each Foo&f in old_vec, second section */) {
swap (f, tmp);
new_vec .push_back (tmp);
}
for (/* each Foo&f in old_vec, third section */) {
swap (f, tmp);
new_vec .push_back (tmp);
}
swap (new_vec, old_vec);
如果Foo有一个move-operator但没有专门的swap
,上面的内容也可能会给C ++ 11带来好的结果。
如果Foo
没有移动语义或其他优化swap
另请注意,如果以上是函数
std::vector<Foo> move (std::vector<Foo> old_vec, ...)`
然后你可以执行整个操作without copying anything, even in C++98但是为了实现这一点,你需要pass by value和不作为参考,这违背了传统的偏好 - 通过参考智慧。