如何在c++中对向量进行切片并分配给它自己
How to slice a vector in c++ and assign to itself?
我想知道如何用矢量的子集替换矢量的内容,而不重新分配新矢量(我发现的每个问题似乎都有分配新矢量的目的)
示例:
vector<int>* testVec = new vector<int>{1, 2, 3, 4, 5};
//do some operation to slice vector, to say {2, 3, 4} without re-allocating
//testVec should now have contents {2, 3, 4}
关于使用范围的问题尚不清楚,但对std::vector::erase
的两次调用就足够了,不会引起任何重新分配。
例如:
std::vector<int> testVec{1, 2, 3, 4, 5};
testVec.erase(testVec.begin() + 4, testVec.end());
testVec.erase(testVec.begin(), testVec.begin() + 1);
通过首先移除向量的尾部,可以确保值只移动一次。
这是完整的代码。
注意,我假设您实际上不需要使用指向std::vector
的指针。
一个简单的方法是使用读/写方法:
int wp = 0; // "write ptr"
int rp = 0; // "read ptr"
for (auto& x : v) {
if (... i want to keep element x, index rp ...) {
if (rp != wp) v[wp] = std::move(x);
wp++;
}
rp++;
}
v.resize(wp);
这种方案也适用于对既依赖于索引又依赖于元素值的条件进行过滤。
您可以使用std::rotate
和vector::erase
的组合
void slice(vector<int> & v, std::size_t start, std::size_t size)
{
assert( v.size() > start + size );
std::rotate( v.begin(), v.begin() + start, v.end() );
// Vector is now {2,3,4,5,1}
v.erase( v.begin() + size, v.end() );
}
只需移除您不想要的部件:
std::vector<int> vec{1, 2, 3, 4, 5};
vec.erase(vec.begin() + 4, vec.end());
vec.erase(vec.begin(), vec.begin() + 1);
这是一个接受谓词的小函数。
对于容器中传递谓词的每个元素,都会从容器中删除该元素。
不进行重新分配,每个元素最多为std::move
'd一次:
template<class C, class F>
void erase_if( C& c, F&& f ) {
using std::begin; using std::end;
auto it = std::remove( begin(c), end(c), std::forward<F>(f) );
c.erase( it, end(c) );
}
对索引执行此操作有点棘手。如果索引是连续的,您可以将第一个索引旋转到第一个位置,然后擦除容器的尾部,或者擦除尾部和前部,或者有多种方法。
如果不是,那么基本上必须编写一个手动版本的std::remove
,该版本适用于索引而不是元素值。
如果你有一个"计数"测试函数来记录它被调用的元素,那么它可能会起作用,但依赖于测试函数的调用顺序似乎过于脆弱。remove_by_index
很简单:
template<class Begin, class End, class Test>
void remove_by_index(Begin b, End e, Test t) {
auto writer = b;
auto reader = b;
std::size_t index = 0;
while (reader != e) {
if (t(index)) {
++reader; ++index;
continue;
}
if (reader != writer) {
*writer = std::move(*reader);
}
++reader; ++writer; ++index;
continue;
}
return writer;
}
给我们:
template<class C, class F>
void erase_by_index( C& c, F&& f ) {
using std::begin; using std::end;
auto it = remove_by_index( begin(c), end(c), std::forward<F>(f) );
c.erase( it, end(c) );
}
假设你想保留所有偶数位置元素的切片:
erase_by_index( vec, [](auto i){return i&1;} );
或者假设我们想保持一个间隔:
template<class C>
void keep_interval( C& c, std::size_t start_index, std::size_t length ) {
erase_by_index(c, [=](auto i){ return i < start_index || i >= (start_index+length); } );
}
现在,一种更通用的方法是创建容器的替代视图,其中视图中的每个元素都对应于原始容器中的某个元素范围,在该视图上进行测试,然后将操作应用回原始容器。
不知道如何写得简明扼要。
相关文章:
- 将数组的地址分配给变量并删除
- vector.resize()中的分配错误
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- Win32编译器选项和内存分配
- 函数中堆分配的效果与缺少堆分配的情况
- 使用动态分配的数组会导致代码分析发出虚假的C6386缓冲区溢出警告
- 多个文件的内存分配错误"在抛出 'std :: bad_alloc' what (): std :: bad_alloc 的实例后终止调用" [C++]
- 获取字符串的长度并将其分配给数组
- 将地址分配给本地指针后,公共对象的变量将消失
- 递归模板化函数不能分配给具有常量限定类型"const tt &"的变量"state"
- 有没有一种方法可以使用placement new将堆叠对象分配给分配的内存
- 我在二维向量中是否正确分配了内存
- 正在尝试重载二进制搜索树分配运算符
- GlobalAlloc而不是其他分配方法
- 自定义先决条件对移动分配运算符有效吗
- 我可以重新分配/覆盖std::字符串吗
- 在c++中使用动态分配的问题
- 当一个新对象被分配到它的地址时,对象是否必须被销毁
- 对共享指针重新分配进行切片
- 如何在c++中对向量进行切片并分配给它自己