STL Vector, Iterator и Insert (C ++) - PullRequest
4 голосов
/ 24 ноября 2011

У меня есть метод, которому передается итератор вектора. В этом методе я хотел бы добавить некоторые элементы в вектор, но я не уверен, возможно ли это при наличии только итератора

void GUIComponentText::AddAttributes(vector<GUIComponentAttribute*>::iterator begin, vector<GUIComponentAttribute*>::iterator end)
{
    for (vector<GUIComponentAttribute*>::iterator i = begin; i != end; ++i)
    {
        GUIComponentAttribute &attrib = *(*i);

        // Here are the GUIComponentAttribute objects analyzed - if an object of a 
        // special kind appears, I would like to add some elements to the vector
    }
}

Спасибо Markus

Ответы [ 4 ]

4 голосов
/ 24 ноября 2011

В показанном вами коде это невозможно.Тем более, что вы не должны добавлять / удалять элементы в / из вектора во время итерации по нему.

3 голосов
/ 24 ноября 2011

Это давняя проблема дизайна в STL. Итераторы не позволяют изменять структуру базовой последовательности, по которой они итерируются: т.е. вы можете изменять (иногда) сами элементы, но не можете добавлять / удалять элементы. Хотя InputIterator и OutputIterator немного особенные в этом отношении ... гул ...

Это на самом деле причина идиомы erase/remove:

vec.erase(std::remove_if(vec.begin(), vec.end(), predicate), vec.end());

Так что нет, извините, на самом деле нет способа изменить вектор.

Однако, как показано выше, вы можете прекрасно использовать алгоритм remove_if и просто вернуть новый конец допустимого диапазона ... или вы можете запросить весь вектор для начала.

Как отметил Бьёрн, изменение структуры последовательности во время ее итерации подвержено ошибкам.

2 голосов
/ 24 ноября 2011

Во-первых, вам придется изменить интерфейс.Учитывая два итератора, невозможно вернуться к контейнеру, на который они ссылаются;поэтому, если вы хотите изменить контейнер, вам нужно будет передать на него ссылку, например:

void GUIComponentText::AddAttributes(
        std::vector<GUIComponentAttribute*>& attributes )
{
    for ( std::vector<GUIComponentAttribute*>::iter = attributes.begin();
            iter != attributes.end();
            ++ iter )
    {
        //  ...
    }
}

Сделав это: вставка может сделать недействительными итераторы.Так что это зависит от того, куда вы хотите вставить.Если вы хотите вставить в текущую позицию: std::vector<>::insert одного элемента возвращает итератор для этого элемента, который был вставлен перед вашим элементом, так что вы можете назначить его своему итератору, настроить (при необходимости) и продолжить:

iter = attributes.insert(iter, newAttribute);
++ iter;   //  Return to where we were...

Если вы добавляете (push_back), проблема немного сложнее;вам нужно вычислить смещение, а затем восстановить итератор:

size_t offset = iter - attributes.begin();
attributes.push_back( nweAttribute );
iter = attributes.begin() + offset;

В этом случае, вероятно, проще выполнить итерацию, используя size_t и [], а не итератор.

0 голосов
/ 24 ноября 2011

Невозможно добавить элементы в вектор во время итерации по нему. Кроме того, вы, безусловно, не можете добавить его в вектор с помощью пары итераторов - вам понадобится указатель / ссылка на весь векторный объект.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...