Надежен ли указатель std :: vector? - PullRequest
1 голос
/ 06 октября 2010

Допустим, у меня есть это:

Object *myObject;
std::vector<Object> objects(99);

....
myObject = &objects[4];

Можно ли предположить, что указатель myObject всегда будет действительным независимо от того, насколько большие объекты получаются [] и если я их удаляю, до тех пор, пока я этого не сделаюкогда-либо стирать () фактический объект, на который указывает myObject?Или это работает по-другому?Если вышеупомянутое не работает, как еще я мог достигнуть этого?Это потому, что в моем дизайне я хочу, чтобы у потомка был указатель на его родителя, который назначается родителем при добавлении потомка, однако родители находятся в std :: vector, мне нужен произвольный доступ.Будет ли std :: list лучше в моем случае?

Спасибо

Ответы [ 4 ]

5 голосов
/ 06 октября 2010

Нет, определенно небезопасно предполагать, что.

Стандарт объясняет, что сделает / не сделает недействительными итераторы в стандартных контейнерах;всякий раз, когда векторный итератор становится недействительным, указатель на него тоже будет.На практике это означает, что когда вектор изменяет размер (включая неявно, когда вы вызываете push_back()), любые итераторы, указывающие на него, будут недействительными, как и ваш указатель.Аналогичным образом, вызов erase() сделает недействительными указатели после стертого элемента, потому что все они должны переместиться вверх, чтобы заполнить стертое пространство.

A std::list будет работать лучше;вы могли бы поддерживать вектор указателей на элементы, который позволял бы вам обращаться к ним по индексу, не перемещая их в памяти.

2 голосов
/ 06 октября 2010

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

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

Другим вариантом может быть deque ;в то время как итераторы deque аннулируются push_back, прямые ссылки на элементы (например, используемый здесь указатель) остаются действительными.

1 голос
/ 06 октября 2010

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

Если вы удалите или добавите элементы, базовое хранилище может быть перераспределено в любое время.

Поскольку вы используете здесь необработанные указатели, вы можете использовать NULL в качестве флага "пустого элемента", чтобы сохранить инвариант хранилища.Поскольку вы устанавливаете его на 99 изначально, все они будут иметь значение NULL после этого (значение по умолчанию для любого указателя в качестве элемента вектора), и reserve является избыточным, если вы не планируете расширять список.Опция, которая позволит вам не беспокоиться о векторном хранилище, будет хранить элементы как boost::shared_ptr<Object>.Тогда любое удаление элемента vector будет фактически delete экземпляром Object, на который ссылаются, если его никто не использует.

boost::shared_ptr<Object> myObject;
std::vector<boost::shared_ptr<Object> > objects(99);

myObject = &objects[4];

objects.clear();
// myObject still valid since Object instance referenced thru shared_ptr
0 голосов
/ 02 марта 2015

Странно, но никто не упомянул вещь boost :: stable_vector вещь:

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

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