C++ remove_if 不遍历整个向量
C++ remove_if without iterating through whole vector
我有一个指针向量,指向大约 10MB 的数据包。在那里,从前 2MB 开始,我想删除所有与我的谓词匹配的内容。这里的问题是 remove_if
遍历整个向量,即使在我的用例中不需要它。还有其他有效的方法吗?
fn_del_first_2MB
{
uint32 deletedSoFar = 0;
uint32 deleteLimit = 2000000;
auto it = std::remove_if (cache_vector.begin(), cache_vector.end(),[deleteLimit,&deletedSoFar](const rc_vector& item){
if(item.ptr_rc->ref_count <= 0) {
if (deletedSoFar < deleteLimit) {
deletedSoFar += item.ptr_rc->u16packet_size;
delete(item.ptr_rc->packet);
delete(item.ptr_rc);
return true;
}
else
return false;
}
else
return false;
});
cache_vector.erase(it, cache_vector.end());
}
在上面的代码中,一旦 deletedSoFar
大于 deleteLimit
,任何超过它的迭代都是不需要的。
std::remove_if()
不需要将.end()
迭代器作为第二个参数传递:只要第一个参数可以递增到第二个参数,任何迭代器都可以传递。
这有点复杂,因为您的条件取决于到目前为止遇到的元素的累积大小。事实证明,似乎 std::remove_if()
不会被使用。像这样的东西应该有效(虽然我不确定 std::find_if()
的这种使用是否真的合法,因为它不断改变谓词):
std::size_t accumulated_size(0u);
auto send(std::find_if(cache_vector.begin(), cache_vector.end(),
[&](rc_vector const& item) {
bool rc(accumulated_size < delete_limit);
accumulated_size += item.ptr_rc->u16packet_size;
return rc;
});
std::for_each(cache_vector.begin(), send, [](rc_vector& item) {
delete(item.ptr_rc->packet);
delete(item.ptr_rc);
});
cache_vector.erase(cache_vector.begin(), send);
std::for_each()
也可以折叠到 std::find_if()
的使用中,但我更喜欢在逻辑上将它们分开。对于足够大的序列,当内存需要两次传输到缓存时可能会出现性能差异。对于引用的微小数字,我怀疑可以测量差异。
而不是 cache_vector.end()
放置您自己的迭代器标记 myIter
。对于 remove_if
选项,您应该遵循 erase-remove 习惯用法。这是一个仅影响前 4 个元素的示例:
#include <iostream>
#include <vector>
#include <algorithm>
int main()
{
std::vector<int> vec = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
size_t index = 4; // index is something you need to calculate
auto myIter = vec.begin() + index; // Your iterator instead of vec.end()
vec.erase(std::remove_if(vec.begin(), myIter, [](int x){return x < 3; }), myIter);
// modified vector:
for (const auto& a : vec)
{
std::cout << a << std::endl;
}
return 0;
}
您可以使用自己的循环:
void fn_del_first_2MB()
{
const uint32 deleteLimit = 2000000;
uint32 deletedSoFar = 0;
auto dest = cache_vector.begin();
auto it = dest
for (; it != cache_vector.end(); ++it) {
const auto& item = *it;
if (item.ptr_rc->ref_count <= 0) {
deletedSoFar += item.ptr_rc->u16packet_size;
delete(item.ptr_rc->packet);
delete(item.ptr_rc);
if (deletedSoFar >= deleteLimit) {
++it;
break;
}
} else if (dest != it) {
*dest = std::move(*it);
++dest;
}
}
cache_vector.erase(dest, it);
}
我有一个指针向量,指向大约 10MB 的数据包。在那里,从前 2MB 开始,我想删除所有与我的谓词匹配的内容。这里的问题是 remove_if
遍历整个向量,即使在我的用例中不需要它。还有其他有效的方法吗?
fn_del_first_2MB
{
uint32 deletedSoFar = 0;
uint32 deleteLimit = 2000000;
auto it = std::remove_if (cache_vector.begin(), cache_vector.end(),[deleteLimit,&deletedSoFar](const rc_vector& item){
if(item.ptr_rc->ref_count <= 0) {
if (deletedSoFar < deleteLimit) {
deletedSoFar += item.ptr_rc->u16packet_size;
delete(item.ptr_rc->packet);
delete(item.ptr_rc);
return true;
}
else
return false;
}
else
return false;
});
cache_vector.erase(it, cache_vector.end());
}
在上面的代码中,一旦 deletedSoFar
大于 deleteLimit
,任何超过它的迭代都是不需要的。
std::remove_if()
不需要将.end()
迭代器作为第二个参数传递:只要第一个参数可以递增到第二个参数,任何迭代器都可以传递。
这有点复杂,因为您的条件取决于到目前为止遇到的元素的累积大小。事实证明,似乎 std::remove_if()
不会被使用。像这样的东西应该有效(虽然我不确定 std::find_if()
的这种使用是否真的合法,因为它不断改变谓词):
std::size_t accumulated_size(0u);
auto send(std::find_if(cache_vector.begin(), cache_vector.end(),
[&](rc_vector const& item) {
bool rc(accumulated_size < delete_limit);
accumulated_size += item.ptr_rc->u16packet_size;
return rc;
});
std::for_each(cache_vector.begin(), send, [](rc_vector& item) {
delete(item.ptr_rc->packet);
delete(item.ptr_rc);
});
cache_vector.erase(cache_vector.begin(), send);
std::for_each()
也可以折叠到 std::find_if()
的使用中,但我更喜欢在逻辑上将它们分开。对于足够大的序列,当内存需要两次传输到缓存时可能会出现性能差异。对于引用的微小数字,我怀疑可以测量差异。
而不是 cache_vector.end()
放置您自己的迭代器标记 myIter
。对于 remove_if
选项,您应该遵循 erase-remove 习惯用法。这是一个仅影响前 4 个元素的示例:
#include <iostream>
#include <vector>
#include <algorithm>
int main()
{
std::vector<int> vec = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
size_t index = 4; // index is something you need to calculate
auto myIter = vec.begin() + index; // Your iterator instead of vec.end()
vec.erase(std::remove_if(vec.begin(), myIter, [](int x){return x < 3; }), myIter);
// modified vector:
for (const auto& a : vec)
{
std::cout << a << std::endl;
}
return 0;
}
您可以使用自己的循环:
void fn_del_first_2MB()
{
const uint32 deleteLimit = 2000000;
uint32 deletedSoFar = 0;
auto dest = cache_vector.begin();
auto it = dest
for (; it != cache_vector.end(); ++it) {
const auto& item = *it;
if (item.ptr_rc->ref_count <= 0) {
deletedSoFar += item.ptr_rc->u16packet_size;
delete(item.ptr_rc->packet);
delete(item.ptr_rc);
if (deletedSoFar >= deleteLimit) {
++it;
break;
}
} else if (dest != it) {
*dest = std::move(*it);
++dest;
}
}
cache_vector.erase(dest, it);
}