C ++ Set Iterator в классе - PullRequest
       24

C ++ Set Iterator в классе

0 голосов
/ 19 января 2011

У меня есть класс, в котором есть член с именем _Emails.Это типа set<PEmail*>.Когда я нахожусь в функции-члене и запускаю следующий код, он работает как положено:

for( set<PEmail*>::iterator it=this->_Emails->begin(); it!=this->_Emails->end(); ++it )
  { 
    cout << "Email: " << (*it)->getEmail() << endl;
  }

То есть выдает список адресов электронной почты.Теперь я хотел бы иметь возможность добавлять к этому набору по мере роста класса и не терять свое место в последней итерации.Я попытался сделать другого члена моего класса с именем _EmailItr типа set<PEmail*>::iterator.Я инициализирую его в своем конструкторе, сразу после _Emails, вот так:

this->_Emails = new set<PEmail*>;
this->_EmailItr = this->_Emails->begin();

Затем, пытаясь сделать аналогичный цикл for:

// send the max queue amount, or until there are no more emails                                         
for( int i=0;  i<this->_QueueSize || i==_Emails->size(); ++i )
  {
    cout << "i: " << i << endl;
    cout << "QueueSize: " << this->_QueueSize << endl;
    cout << "Emails: " << this->_Emails->size() << endl;

    cout << (*_EmailItr)->getEmail() << endl;
  }

, я получаю следующий вывод:1012 *

i: 0
QueueSize: 2
Emails: 2
Segmentation fault

Что дает?Я пытаюсь использовать итераторы ненадлежащим образом?

Ответы [ 3 ]

4 голосов
/ 19 января 2011

Когда вы получаете this->_Emails->begin() сразу после создания std::map, получаемый итератор является конечным итератором (поскольку в std::map нет элементов, его размер равен нулю и begin() == end()). Вы не можете разыменовать или увеличивать конечный итератор. Это не указывает на «начало контейнера»; он указывает на «элемент, который в данный момент находится в начале» или, если контейнер пуст, он возвращает конечный итератор.

(На несвязанной заметке похоже, что вы делаете слишком много динамического выделения. Почему вы динамически создаете объект std::set (используя new)? Почему бы просто не иметь std::set в качестве члена класс?)

2 голосов
/ 19 января 2011

Когда вы сначала создаете набор _Emails, а затем устанавливаете _EmailItr в _Emails->begin(), итератор ни на что не указывает.Фактически он указывает на _Emails->end(), поскольку, когда набор пуст, begin() и end() одинаковы.

Итак, позже вы попытаетесь разыменовать итератор, который указывает на end(), что является неопределенным поведением и приводит к вашей аварии.

Вы, похоже, предполагаете, что итератор фактически каким-то образом "обновляется" за кулисами, когда вы добавляете новые объекты в список.Это не.Это всегда указывает на end().Вам нужно установить значение _Emails->begin() после того, как вы вставите элементы в набор.


Также, не имеет отношения к вашему вопросу, но: есть ли какая-то причина, по которой вам нужно выделить _Emails в куче?

1 голос
/ 19 января 2011

STL set хорошо ведет себя при вставке новых элементов во время итерации. В частности, если вы перебираете set при добавлении новых элементов, вы не «потеряете след» того, где находитесь; Ваш итератор останется действительным и будет видеть все новые элементы, которые были добавлены или удалены. Я не совсем уверен, какой у вас вариант использования, но я не думаю, что вам нужны все дополнительные механизмы, которые вы представили здесь. Просто использование старого доброго итератора без каких-либо украшений должно работать очень хорошо.

...