C ++ - Безопасность доступа к элементу вектора через указатели

В моем проекте на C ++ я использую vector для хранения кучи struct, которые содержат ряд элементов для простой игры (например, крестики-нолики, координаты, x против o и т. Д.). то есть:

struct gameMove
{
  int x;
  int y;
  int player;
  int order;
};

Каждый раз в течение одной игры, всякий раз, когда игрок делает ход (т. Е. Ставит x или o), информация сохраняется в vector через push_back(), чтобы создать функцию «отменить», которая в настоящее время работает должным образом.

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

Насколько это безопасно, если я правильно управляю vector, обращаюсь к нему, убираю NULL все указатели, указывающие на элементы vector, или есть неотъемлемые риски? Меня беспокоит то, что если расширить игру, что я планирую сделать (то есть: использовать тот же код для шахматной партии, над которой я работаю), и что vector становится слишком большим и его необходимо автоматически перераспределить, указатели станет недействительным (то есть: весь список перемещен в новый непрерывный блок, который может вместить все элементы), или существует ли какой-то тип интерфейса интеллектуального указателя на vector для выполнения того же самого?

Спасибо.


person Cloud    schedule 27.07.2015    source источник


Ответы (2)


Вы правы, если беспокоитесь: если вектор должен расти, адреса в vector изменятся (или если вектор сжимается, но большинство реализаций vector не сжимаются без некоторых усилий со стороны программиста).

Непосредственно простым решением было бы вернуть индекс в вектор вместо указателя. Это всегда будет действенным способом найти конкретный элемент, пока он находится в пределах досягаемости. [И вместо NULL вы можете использовать, например, -1 или 0xDEAD]

person Mats Petersson    schedule 27.07.2015
comment
Если я точно знаю верхний предел количества элементов в vector, можно ли заранее установить максимальный размер vector, гарантируя, что он никогда не изменится? - person Cloud; 28.07.2015
comment
@Dogbert Вы можете использовать reserve для выделения необходимой памяти заранее, но зачем беспокоиться, если вы можете использовать индекс, а не указатель, как упоминалось в этом ответе? - person JorenHeit; 28.07.2015
comment
Как уже упоминалось, reserve гарантирует, что vector не будет перераспределен [до тех пор, пока не будет достигнут зарезервированный предел], но я не вижу выгоды ... Если вы не планируете более 4 миллиардов записей, указатели будут больше, чем целые числа [в 64-битных архитектурах, что в наши дни является нормой, даже на мобильных телефонах!] - person Mats Petersson; 28.07.2015
comment
Если что-то не изменилось в C ++ 11, vector гарантированно не перераспределится при удалении элементов или при вызове reserve() со значением, меньшим, чем текущая емкость. Из 23.2.4.2/2 стандарта C ++ 03: перераспределение происходит в этот момент тогда и только тогда, когда текущая емкость меньше аргумента резервной (). - person j_random_hacker; 28.07.2015
comment
@JorenHeit Причина, по которой я хотел бы избежать индексного подхода, заключается в том, что для этого потребуется внутренняя перезапись API, чего я бы хотел избежать, если это безопасно, и, возможно, использование глобальной переменной. - person Cloud; 28.07.2015
comment
Одна вещь, которую я также забыл спросить: если я удалю некоторые элементы из vector через erase_at(), добавляю новые элементы через push_back(), повторно использую освободившееся пространство в непрерывном списке, или вместо этого он просто добавляется в список. Я знаю, что использую не более 50 элементов, но во время тестирования могу несколько раз добавлять / удалять элементы. Спасибо! - person Cloud; 28.07.2015
comment
Кроме того, если я сохраню индекс, а позже мне придется удалить какой-то произвольный элемент через erase_at(), то значения индекса больше не действительны. - person Cloud; 28.07.2015
comment
Это относится и к указателям - если у вас есть указатель на элемент 6, и вы стираете элемент 4, тогда указатель теперь должен указывать на новый элемент 5, но на самом деле он указывает на новый элемент 6, так что точно такая же проблема. - person Mats Petersson; 28.07.2015

Вы рассматривали возможность использования std::stack или std::list? Стек может быть особенно привлекательным для упрощения функции «отмены», которую вы ищете (поскольку последний ход всегда будет вершиной стека). Но со связанной структурой вам не нужно так сильно беспокоиться о проблеме индексации, хотя, если у вас мало памяти, они могут быть не лучшим вариантом ...

person Tyler    schedule 27.07.2015