Указатели на элементы станд.:: вектор и станд.:: список

У меня есть a std::vector с элементами некоторого класса ClassA. Дополнительно я хочу создать индекс с помощью a std::map<key,ClassA*> который отображает некоторое значение ключа на указатели на элементы, содержавшиеся в векторе.

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

std::vector<ClassA> storage;
std::map<int, ClassA*> map;

for (int i=0; i<10000; ++i) {
  storage.push_back(ClassA());
  map.insert(std::make_pair(storage.back().getKey(), &(storage.back()));
}
// map contains only valid pointers to the 'correct' elements of storage

Как ситуация, если я использую std::list вместо std::vector?

29
задан MartinStettner 20 July 2010 в 07:23
поделиться

6 ответов

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

Списки - Да, вставка и удаление элементов не делает недействительными указатели, ссылки и итераторы на другие элементы

25
ответ дан 28 November 2019 в 01:43
поделиться

Насколько я понимаю, такой гарантии нет. Добавление элементов в вектор приведет к перераспределению элементов, что приведет к недействительности всех ваших указателей на карте.

9
ответ дан 28 November 2019 в 01:43
поделиться

Я не уверен, гарантируется ли это, но на практике storage.reserve (required_size) должен гарантировать отсутствие перераспределения.

Но почему вы не храните индексы?
Индексы легко преобразовать в итераторы, добавив их к начальному итератору ( storage.begin () + idx ), и любой итератор легко превратить в указатель, сначала разыменовав его, а затем взяв его адрес ( & * (storage.begin () + idx) ).

3
ответ дан 28 November 2019 в 01:43
поделиться

Просто заставьте их оба хранить указатели и явно удалять объекты, когда они вам не нужны.

std::vector<ClassA*> storage;
std::map<int, ClassA*> map;

for (int i=0; i<10000; ++i) {
  ClassA* a = new ClassA()
  storage.push_back(a)
  map.insert(std::make_pair(a->getKey(), a))
}
// map contains only valid pointers to the 'correct' elements of storage
1
ответ дан 28 November 2019 в 01:43
поделиться

Используйте std :: deque ! Указатели на элементы стабильны, когда используется только push_back () .

Примечание. Итераторы элементов могут быть недействительными! Указателей на элементы не будет.

Изменить: этот ответ объясняет детали, почему: Итератор C ++ deque недействителен после push_front ()

6
ответ дан 28 November 2019 в 01:43
поделиться

Из одного из комментариев к другому ответу, кажется, что все, что вы хотите, это централизовать (облегчить) управление памятью. Если это действительно так, вам следует рассмотреть возможность использования готовых решений, таких как библиотека boost pointer container, и максимально упростить свой собственный код.

В частности, посмотрите на ptr_map

1
ответ дан 28 November 2019 в 01:43
поделиться
Другие вопросы по тегам:

Похожие вопросы: