расположение векторных указателей гарантировано? - PullRequest
8 голосов
/ 05 января 2012

Предположим, у меня есть вектор целых чисел,

std::vector<int> numbers;

, который заполнен кучей значений, тогда я говорю, сделайте это (где запись существует в 43)

int *oneNumber = &numbers[43];

Гарантируется ли oneNumber всегда указывать на int в индексе 43, даже если я скажу, что я изменяю размеры чисел к чему-то вроде numbers.resize (46)?

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

Ответы [ 7 ]

7 голосов
/ 05 января 2012

Гарантируется ли oneNumber всегда указывать на int по индексу 43

Да, это гарантируется стандартом.

даже если я скажу, что я изменяю размеры чисел к чему-то вроде numbers.resize (46)?

Нет. После изменения размера, добавления или удаления чего-либо в векторе все адреса и итераторы к нему становятся недействительными. Это потому, что вектор может потребоваться перераспределить с новыми ячейками памяти.

4 голосов
/ 07 октября 2012

Как и все остальные, когда вы вызываете .resize() для вектора, ваши указатели становятся недействительными, потому что (старый массив) может быть полностью освобожден, а совершенно новый может быть перераспределен, а ваши данные скопированы в него .

Одним из способов решения этой проблемы является . Не храните указатели в векторе STL. Вместо этого хранит целочисленные индексы .

Итак, в вашем примере,

std::vector<int> numbers;
int *oneNumber = &numbers[43]; // no. pointers invalidated after .resize or possibly .push_back.
int oneNumberIndex = 43 ;      // yes. indices remain valid through .resize/.push_back
4 голосов
/ 05 января 2012

Указатели, ссылки и итераторы на элементы std::vector гарантированно остаются на месте, пока вы добавляете только к std::vector и размер std::vector не превышает егоcapacity() во время получения указателя, ссылки или итератора.Как только его размер превышает capacity(), все указатели, ссылки и итераторы этого std::vector становятся недействительными.Обратите внимание, что все становится недействительным и при вставке в другое место, кроме конца std::vector.

Если вы хотите, чтобы ваши объекты оставались на месте, и вы вставляете только новые элементы в конце или начале, вы можетеиспользуйте std::deque.Указатели и ссылки на элементы в std::deque становятся недействительными только при вставке в середину std::deque, или при удалении из середины, или при удалении ссылочного объекта.Обратите внимание, что итераторы для элементов в std::deque становятся недействительными каждый раз, когда вы вставляете элемент в std::deque или удаляете любой элемент из него.

4 голосов
/ 05 января 2012

Ваша паранойя верна. Изменение размера std::vector может привести к изменению местоположения в памяти. Это означает, что ваш oneNumber теперь указывает на старую область памяти, которая была освобождена, и поэтому доступ к ней - неопределенное поведение.

2 голосов
/ 05 января 2012

Как только вы изменили емкость вектора, данные были скопированы в другой блок памяти, а исходные данные удалены.

2 голосов
/ 05 января 2012

Когда вы используете векторную функцию resize () или reserve () для увеличения емкости вектора, может потребоваться перераспределение памяти для поддержки массива.Если он перераспределится, новая память не будет расположена по тому же адресу, поэтому адрес, сохраненный в oneNumber, больше не будет указывать на правильное место.

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

2 голосов
/ 05 января 2012

Нет - вектор может быть перераспределен по мере роста.Обычно, когда вектор удваивается в размере.

Из стандарта C ++ 11

1 Remarks: Causes reallocation if the new size is greater than the old capacity. If no
reallocation happens, all the iterators and references before the insertion point
remain valid. If an exception is thrown other than by the copy constructor, move 
constructor, assignment operator, or move assignment operator of T or by any 
InputIterator operation there are no effects. If an exception is thrown by the move 
constructor of a non-CopyInsertable T, the effects are unspecified.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...