Существует ли стандартный контейнер, который позволяет вставлять элементы без аннулирования итераторов? - PullRequest
0 голосов
/ 10 февраля 2012

В C ++ есть ли структура данных, которая позволяет мне добавлять элементы к ней в следующем цикле for?

(я использовал list в качестве примера, потому что это то, что я пробовал до сих пор)элементы из вектора

Ответы [ 4 ]

3 голосов
/ 10 февраля 2012

Этот ответ о StackOverflow дает хорошее резюме поведения всех стандартных контейнеров.

Контейнеры, которые не будут делать недействительными итераторы при вставке или удалении, listset, multiset, map и multimap.Конечно, это исключает стирание итератора.

1 голос
/ 11 февраля 2012

Написание этого за запрос.

PS: это дополнительный вопрос для удаления элементов из вектора

Это тревожный шаблон в вашей линии допроса.

Серьезно, модификация контейнеров во время их итерации - это плохо. Трудно получить права. Это часто не спасает вас с точки зрения производительности. Редко (за исключением ограниченного числа случаев, когда есть стандартный библиотечный алгоритм, точно соответствующий вашим потребностям), его легче выразить. Это может быть очень дорого в производительности, если вы делаете это неправильно. Это может быть очень дорого с точки зрения правильности программы, если вы делаете это неправильно, что гораздо важнее всего остального.

Это становится экспоненциально хуже, если задействуется многопоточность. Java имеет специальный тип исключений специально для определенных вещей, которые могут пойти не так, когда вы пытаетесь это сделать. В C ++ вам не так повезло; аналогичная проблема может быть не обнаружена.

Просто напишите код, который дает конечный результат, а затем замените оригинальный контейнер. Единственное, что действительно может замедлить это, это «копировать экземпляры дорого», и в этом случае вы уже должны использовать слой косвенности для решения проблемы (если она действительно имеет значение).

list<Elem> original;
// fill elems with some Elems;
list<Elem> modified;
for (
    list<Elem>::iterator it = original.begin(), end = original.end();
    it != end; ++it
) {
    if (something()) {
        modified.push_back(*it);
    } else if (something_else()) {
        modified.push_back(Elem()); // for example
    }
    // else, 'erase' the element by just not putting anything into 'modified'
    // Or we could do whatever other combination of things,
    // maybe insert more than one
}
std::swap(original, modified);
1 голос
/ 10 февраля 2012

Да, list позволяет вам сделать это .. как я сказал в своем комментарии в другом ответе ...

0 голосов
/ 10 февраля 2012

Есть несколько контейнеров , которые поддерживают вставку без аннулирования итераторов.В вашем коде у вас есть правильный случай удаления, но я полагаю, что вы слишком продуманны для случая вставки.Попробуйте это:

else {
    Elem elem;
    elems.push_back(elems);
    ++it;
}

В данном примере вы используете list, поэтому вы знаете, что вызов push_back не сделает недействительным it.Таким образом, вы можете просто увеличить его, чтобы перейти к следующему элементу.Вы должны быть осторожны, когда удаляете элементы , потому что вы не можете увеличить итератор, который указывает на место, которое больше не существует.

...