Указатели на элементы в контейнере - PullRequest
4 голосов
/ 02 апреля 2010

Скажите, у меня есть объект:

struct Foo 
{
    int bar_;
    Foo(int bar) bar_(bar) {}
};

, и у меня есть контейнер STL, который содержит Foo s, возможно, вектор, и я беру

// Elsewhere...

vector<Foo> vec;

vec.push_back(Foo(4));

int *p = &(vec[0].bar_)

Это ужасная идея, верно?

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

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

Ответы [ 4 ]

11 голосов
/ 02 апреля 2010

Стандарт определяет, когда такие указатели становятся недействительными. Ссылки на vector умирают, когда вы увеличиваете его размер после capacity или добавляете / удаляете предыдущий элемент. Ссылки на deque становятся недействительными, если вы добавляете / удаляете из середины.

В противном случае ссылки и итераторы безопасны для срока службы базового объекта.

1 голос
/ 02 апреля 2010

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

Например, вот некоторый частичный текст, описывающий некоторые эффекты функции-резерва вектора:

  Notes:
    Reallocation invalidates all the references, pointers, and iterators
    referring to the elements in the sequence. 

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

Лучше всего проверить, что говорится в стандарте для вашего конкретного контейнера и функции-члена.

1 голос
/ 02 апреля 2010

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

0 голосов
/ 02 апреля 2010

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

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