Преобразование const auto & в итератор

Ряд сообщений, которые я прочитал в последнее время, утверждают, что for(const auto &it : vec) совпадает с использованием более длинного синтаксиса итератора for(std::vector<Type*>::const_iterator it = vec.begin(); it != vec.end(); it++). Но я наткнулся на этот пост, в котором говорится, что они не совпадают.

В настоящее время я пытаюсь стереть элемент в цикле for после его использования, и мне интересно, есть ли способ преобразовать const auto &it : nodes в std::vector<txml::XMLElement*>::iterator?

Рассматриваемый код:

std::vector<txml2::XMLElement *> nodes;
//...
for (const auto &it : nodes)
{
    //...       
   nodes.erase(it);
}

Я почти уверен, что мог бы просто переписать std::vector<txml2::XMLElement*> как константный указатель, но предпочел бы этого не делать, так как этот код в данный момент предназначен только для отладки.


person ZeroPhase    schedule 31.05.2016    source источник


Ответы (2)


Вы не должны пытаться преобразовать объявление диапазона в вашем диапазоне на основе цикла for в итератор, а затем удалить его во время итерации. Даже настройка итераторов во время итерации опасна, и вместо этого вы должны полагаться на алгоритмы.

Вы должны использовать Erase-remove_idiom.
Вы можете использовать с помощью remove_if.

Это будет выглядеть примерно так:

  nodes.erase( std::remove_if(nodes.begin(), nodes.end(), [](auto it){

    //decide if the element should be deleted
    return true || false;

  }), nodes.end() );

В настоящее время в технических спецификациях указано erase_if.
Это более чистая версия того же поведения, показанного выше:

std::erase_if(nodes,[](auto it){

    //decide if the element should be deleted
    return true || false;
});
person Trevor Hickey    schedule 01.06.2016
comment
Спасибо, это была огромная помощь. В конце концов я просто использовал set_difference, но это привело меня на правильный путь. - person ZeroPhase; 01.06.2016

Вы получаете не итератор, а ссылку на элемент. Если вы не хотите делать с ним std::find, довольно сложно получить из него итератор.

Векторы хороши, поэтому вы можете увеличить счетчик на элемент и сделать nodes.begin() + counter, чтобы получить итератор, но это как бы лишило смысла.

Также стирание итератора в цикле for приведет к повторению после окончания вектора, вы можете протестировать этот код:

#include <iostream>
#include <vector>

using namespace std;

int main() {
    vector<int> v = {0,1,2,3,4,5,6};

    for (int x : v) {
        cout << x << endl;

        if (x == 2) {
            v.erase(v.begin() + 2);
        }
    }
    return 0;
}

Если вы хотите использовать итераторы, просто выполните с ними цикл, если, кроме того, вы хотите стереть один средний цикл, вам нужно следовать this ответ:

for (auto it = res.begin() ; it != res.end(); ) {
  const auto &value = *it;

  if (condition) {
    it = res.erase(it);
  } else {
    ++it;
  }
}

Обратите внимание, что вам не нужно указывать весь тип итератора, auto работает так же хорошо.

person coyotte508    schedule 01.06.2016