Home > front end >  C erasing section of vector with a size_t as start point
C erasing section of vector with a size_t as start point

Time:09-28

I want to erase a section of a std::vector e.g ith element through end. Where i is a std::size_t that is calculated beforehand.

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());

I get a Conversion may change the sign of the result warning

I tried using std::next but that still results in the same warning

The only why I found that gets rid of the warning, but I think is very unelegant is

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

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

Is there any good solution to get rid if this warning?

EDIT:

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());
}

Results in following error

../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());
      |  

Compiled with g version 9.3.0 and c 17

CodePudding user response:

The code shown is perfectly fine, AFAICS. The warning implies that the vector's implementation is in the wrong, not you. A vector::iterator can be incremented by an index, and your index variable is the same type that vector uses for its indexes. So there should be no conversion. But there is, because the difference_type of the iterator is not the same type as the size_type of the vector.

In any case, this kind of code is unnecessary anyway. You could just use the Erase-Remove idiom via std::remove_if() vector::erase(), or std::erase_if() in C 20. Then there would be no need to handle these kinds of loops and swaps manually at all. For example:

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); });
}
  • Related