У меня есть 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
?
Векторы - Нет. Поскольку емкость векторов никогда не уменьшается, гарантируется, что ссылки, указатели и итераторы остаются действительными даже при удалении или изменении элементов, при условии, что они относятся к позиции перед управляемые элементы. Однако вставки могут сделать недействительными ссылки, указатели и итераторы.
Списки - Да, вставка и удаление элементов не делает недействительными указатели, ссылки и итераторы на другие элементы
Насколько я понимаю, такой гарантии нет. Добавление элементов в вектор приведет к перераспределению элементов, что приведет к недействительности всех ваших указателей на карте.
Я не уверен, гарантируется ли это, но на практике storage.reserve (required_size)
должен гарантировать отсутствие перераспределения.
Но почему вы не храните индексы?
Индексы легко преобразовать в итераторы, добавив их к начальному итератору ( storage.begin () + idx
), и любой итератор легко превратить в указатель, сначала разыменовав его, а затем взяв его адрес ( & * (storage.begin () + idx)
).
Просто заставьте их оба хранить указатели и явно удалять объекты, когда они вам не нужны.
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
Используйте std :: deque
! Указатели на элементы стабильны, когда используется только push_back ()
.
Примечание. Итераторы элементов могут быть недействительными! Указателей на элементы не будет.
Изменить: этот ответ объясняет детали, почему: Итератор C ++ deque недействителен после push_front ()
Из одного из комментариев к другому ответу, кажется, что все, что вы хотите, это централизовать (облегчить) управление памятью. Если это действительно так, вам следует рассмотреть возможность использования готовых решений, таких как библиотека boost pointer container, и максимально упростить свой собственный код.
В частности, посмотрите на ptr_map