Ошибки, связанные с reverse_iterator, в Visual C ++.Это юридический код? - PullRequest
0 голосов
/ 14 декабря 2011

Сегодня я поиграл с некоторым кодом и был очень удивлен, обнаружив, что следующий код вылетает в Visual C ++. Это выглядит хорошо? GCC выводит 1, когда я запускаю код. Как и Intel.

#include <iostream>
#include <set>
#include <assert.h>

int main()
{
    std::set<int> sampleSet;
    sampleSet.insert(1);
    sampleSet.insert(2);
    sampleSet.insert(3);
    std::set<int>::iterator normalIt(sampleSet.begin());
    std::set<int>::reverse_iterator reverseIt(sampleSet.rbegin());

    ++normalIt;
    ++reverseIt;

    int test1(*reverseIt); // 2
    assert(*normalIt == *reverseIt); //they're both = 2
    std::set<int>::iterator gonnaDelete((++reverseIt).base()); // gonnaDelete points to 2
    int test2(*reverseIt); // 1
    sampleSet.erase(gonnaDelete);
    int test3(*reverseIt); // 1???   Visual Studio 2010 crashes here.... gcc is fine, but not sure if this is legal
    std::cout << test3 << std::endl;

    return 0;
}

Ответы [ 2 ]

1 голос
/ 14 декабря 2011

Это не законно.Согласно [lib.associative.reqmts] в C ++ 98, «члены стирания должны делать недействительными только итераторы и ссылки на стертые элементы».Так как reverse_iterator определен примерно так:

template<typename Iter>
class reverse_iterator {
  Iter current;
  Iter tmp;
 public:
  ...
  Iter base() { return current; }
  reference operator*() {
    tmp = current;
    --tmp;
    return *tmp;
  }
};

при удалении gonnaDelete вы также лишаете законной силы reverseIt.current, поэтому при последующем разыменовании reverseIt вы получаете неопределенное поведение.

Теперьитераторы набора, как правило, являются простыми указателями на узлы, а оптимизированные распределители иногда оставляют память удаленного узла в одиночку, поэтому иногда случается, что код выполняет то, что вы ожидаете, даже после того, как вы аннулировали один из них, но это совсем не гарантируетсяработать.Я подозреваю, что VC ++ имеет режим отладки по умолчанию, чтобы поймать такую ​​ошибку.Чтобы включить эквивалентный режим gcc, попробуйте собрать с -D_GLIBCXX_DEBUG: http://gcc.gnu.org/onlinedocs/gcc-4.6.2/libstdc++/manual/manual/bk01pt03ch17s03.html

1 голос
/ 14 декабря 2011

std :: vector :: erase (i) делает недействительными любые итераторы, ссылающиеся на векторные элементы до «i»

MSDN Reference

...