Итератор для vec.end () остается действительным после vec.push_back (), когда перераспределения нет - PullRequest
1 голос
/ 22 марта 2011

Допустим ли этот пример кода?

#include<vector>
using namespace std;

int main() {
  vector<int> vec(10); // create with 10 elements
  vec.reserve(100);    // set capacity to 100
  vector<int>::iterator iter = vec.end(); // points 1 past vec[9]

  vec.push_back( 777 );

  bool is_this_valid_and_true =  *iter == vec[10]; // ?

  // VS2010 runtime error in debug build:
  // Expression: vector iterator not dereferencable
  // Works in release build

  iter = vec.end() + 1; // points 2 past vec[10]?
  vec.push_back( 888 );
  vec.push_back( 999 );

  is_this_valid_and_true =  *iter == vec[12]; // ?
}

Ошибка в VS2010 может быть связана с этим ошибка .

Если я установилпараметр командной строки /D_HAS_ITERATOR_DEBUGGING=0 или установить

#define _HAS_ITERATOR_DEBUGGING 0
#include<vector>

ошибки нет.

Редактировать:

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

Ответы [ 2 ]

7 голосов
/ 22 марта 2011

23.2.4.3 / 1:

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

Так что нет, end() не обязательно должен быть действительным после push_back.Цитата относится к vector.insert, push_back определяется как insert

6 голосов
/ 22 марта 2011

Вы рассматриваете итераторы как указатели.

Итераторы могут использовать указатели в качестве подробностей реализации, но они не являются фактическими указателями.

Таким образом:

iter = vec.end() + 1; // This is not valid.

Тамнет такой вещи, как два элемента передают конец данных.

vec.end () возвращает итератор, который, когда декремент является ссылкой на последние элементы (при условии, что есть элементы).Хотя итератор, ссылающийся на последний элемент при увеличении, эквивалентен итератору, возвращаемому функцией end ().

// Note: Assuming vector iterators were not invalidated after an insert anyway.
//       But for arguments sake lets play this out.
//
vector<int>::iterator iter = vec.end(); // points 1 past vec[9]
vec.push_back( 777 );
bool is_this_valid_and_true =  *iter == vec[10]; // Not valid.
                                                 // This is the end() iterator
                                                 // de-referencing it is UB

Но отмена ссылки на итератор, представленный функцией end (), является неопределенным поведением () (даже если у вас естьзарезервированное пространство) (реализация может не использовать указатели. Например, некоторые реализации DeBug STL будут выполнять расширенную проверку ошибок в коде итератора).

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