Переключение векторов, поставляемых итераторами - PullRequest
0 голосов
/ 27 мая 2020

Я разрабатываю свой собственный c контейнер дерева и использую STL в качестве справочника. Однако при реализации моего класса итератора я заметил кое-что об использовании итераторов в STL.

Например, класс std::vector полагается на итераторы в качестве аргументов для многих своих методов. (ie. erase(const_iterator position))

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

// Example program
#include <iostream>
#include <string>
#include <vector>
#include <iomanip>

void printVec(const std::string &label, const std::vector<int> &vec){
    for (unsigned int i=0; i<vec.size(); i++){
        std::cout << ::std::setw(3) << vec[i] << ", ";
    }
    std::cout << std::endl;
}

int main()
{
  std::vector<int> test={0,1,2,3,4,5,6,7,8,9};
  std::vector<int> test2{10,11,12,13,14,15,16,17,18,19};
  std::vector<int>::iterator iter=test.begin();
  std::vector<int>::iterator iter2=test2.begin();

  printVec("One",test);
  printVec("Two",test2);

  for (int i=0; i<5; i++, iter++, iter2++);
  std::cout << "One Pos: " << *iter << std::endl;
  std::cout << "Two Pos: " << *iter2 << std::endl;
  test.erase(iter2);    //Switching the iterators and there respective vectors
  test2.erase(iter);    //Switching the iterators and there respective vectors

  printVec("One",test);
  printVec("Two",test2);
}

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

1 Ответ

1 голос
/ 27 мая 2020

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

Простого способа избежать этого нет. Самое близкое, что вы можете сделать, - это проверить итераторы, что означает, что вам нужно будет отслеживать контейнер, к которому принадлежит каждый итератор. Это немного усложняется с некоторыми операциями, такими как swap или insert, которые не аннулируют существующие итераторы, но оставляют их ссылкой на новый контейнер.

Некоторые компиляторы, такие как Visual C ++, при компиляции в режиме отладки, может обнаруживать подобные проблемы во время выполнения и выдавать соответствующее уведомление.

...