C++ 以 size_t 作为起点擦除向量部分

C++ erasing section of vector with a size_t as start point

我想擦除 std::vector 的一部分,例如 iend 的元素。其中 i 是预先计算的 std::size_t

auto i = vec.size();

for (auto pos = vec.size(); pos > 0; --pos) {
  auto& elem = vec.at(pos - 1);

  if (*magic_condition*) {
    --i;
  }
}

vec.erase(vec.begin() + i, vec.end());

我收到 Conversion may change the sign of the result 警告

我尝试使用 std::next,但仍然会产生相同的警告

我发现去掉警告的唯一原因是

const auto begin = typename decltype(vec)::const_iterator{vec.data() + i};

vec.erase(begin, vec.end());

如果出现这个警告,有什么好的解决办法可以解决吗?

编辑:

void update(const delta_type delta) {
  auto size = handlers.size();

  for(auto itr = handlers.rbegin(); itr != handlers.rend(); ++itr) {
    auto& handler = *itr;

    if(const auto dead = handler.update(handler, delta); dead) {
      std::swap(handler, handlers.at(--size));
    }
  }

  handlers.erase(handlers.begin() + size, handlers.end());
}

导致以下错误

../ecs/scheduler.hpp: In instantiation of ‘void sbx::scheduler<Delta>::update(sbx::scheduler<Delta>::delta_type) [with Delta = float; sbx::scheduler<Delta>::delta_type = float]’:
/home/kabelitzj/Dev/sandbox/sandbox/core/engine.cpp:39:29:   required from here
../ecs/scheduler.hpp:64:39: warning: conversion to ‘__gnu_cxx::__normal_iterator<sbx::scheduler<float>::process_handler*, std::vector<sbx::scheduler<float>::process_handler, std::allocator<sbx::scheduler<float>::process_handler> > >::difference_type’ {aka ‘long int’} from ‘long unsigned int’ may change the sign of the result [-Wsign-conversion]
   64 |     handlers.erase(handlers.begin() + size, handlers.end());
      |  

使用 g++ version 9.3.0c++17

编译

显示的代码非常好,AFAICS。警告暗示 vector 的实现是错误的,而不是你。 vector::iterator 可以通过索引递增,并且您的索引变量与 vector 用于其索引的类型相同。所以应该没有转换。但是有,因为迭代器的difference_typevectorsize_type不是同一个类型。

不管怎样,这种代码反正是没有必要的。您可以只使用 C++20 中的 Erase-Remove idiom via std::remove_if()+vector::erase(), or std::erase_if()。那么就根本不需要手动处理这些类型的循环和交换。例如:

vec.erase(
    std::remove_if(vec.begin, vec.end(),
        [](auto &elem){ return *magic_condition*; }
    ),
    vec.end()
);
std::erase_if(vec, [](auto &elem){ return *magic_condition*; });
void update(const delta_type delta) {
  handlers.erase(
    std::remove_if(handlers.begin(), handlers.end(),
      [&](auto &handler){ return (bool) handler.update(handler, delta); }
    ),
    handlers.end()
  );
}
void update(const delta_type delta) {
  std::erase_if(handlers, [&](auto &handler){ return (bool) handler.update(handler, delta); });
}