Как сохранить указатели на структуры, хранящиеся в векторе, действительными?

Я изучаю С++, и у меня проблемы с указателями на структуры, хранящиеся в векторе. Проблема в том, что мне нужно дважды отсортировать структуру Student. Один раз по идентификатору учащегося, а другой раз по имени учащегося, чтобы в нем было легко искать значения. Из-за этого я создал два вектора указателей:

vector<Student *> sortedByID;    
vector<Student *> sortedByName;

Структура выглядит так, и я также сохраняю ее в векторе (хотя, вероятно, это не очень хорошая идея):

struct Student {
    int id;
    string name;
};

vector <Student> students;

Я создаю новую структуру с помощью push_back и заполняю ее параметрами из функции (да, у меня есть конструктор). Чтобы отсортировать вектор указателей, я использую lower_bound, как показано ниже:

students.push_back(Student(id, name));
it = lower_bound(sortedByID.begin(), sortedByID.end(), id, cmp());
sortedByID.insert(it, &(students.back()));
//the same for name

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

Есть ли какой-то умный способ решить эту проблему? Обратите внимание, что мне разрешено использовать только вектор, а не какие-либо другие контейнеры из STL.


person Filip N.    schedule 30.03.2016    source источник
comment
Вы не можете, скорее используйте индексы для такого случая. Они не изменятся, даже если вектор перераспределит свой внутренний массив.   -  person πάντα ῥεῖ    schedule 30.03.2016
comment
Вы можете сделать отсортированные векторы векторами целых чисел, которые индексируются в students. Конечно, тогда вы должны убедиться, что не удаляете из середины students без пересчета сортировки.   -  person M.M    schedule 30.03.2016
comment
Вам разрешено использовать только vector, да? Не похоже на реальную проблему мира не так ли? :закатывать глаза:   -  person mainactual    schedule 31.03.2016
comment
Включите код, достаточный для создания MCVE.   -  person TriskalJM    schedule 31.03.2016
comment
Это также зависит от того, как часто фактически манипулируют массивом vector. Если он заполняется только один раз и вы заранее знаете размер вектора или массива, адреса памяти не изменятся.   -  person Mark Nunberg    schedule 31.03.2016
comment
@mainactual Нет, это часть школьного проекта, который я изменил, чтобы его было легче понять.   -  person Filip N.    schedule 31.03.2016
comment
Я мог догадаться :). Как и у Кристофа 3), я бы использовал std::map< int, std::shared_ptr<Student> > и std::multimap< std::string, std::shared_ptr<Student> >. Это отвечает на вопрос о сохранении указателей в силе. vectorизация зависит от вас.   -  person mainactual    schedule 31.03.2016


Ответы (1)


Есть три варианта решения этой проблемы, используя только векторы и никакие другие контейнеры:

1) Избегайте перераспределения. Это может быть достигнуто только в том случае, если вы знаете максимальное M ожидаемого количества элементов, которые будут вставлены в ваш вектор. В этом случае вы можете students.reserve(M);.

2) Забудьте указатели на sortedByID и sortedByName. Используйте целые числа (или, лучше сказать, size_t), сохраняйте индекс студента в students вместо указателя. Это предполагает, конечно, что порядок предметов у студентов никогда не меняется.

3) Не хранить самих учеников в векторе, а сделать students вектором указателей на учеников (несортированных), которые выделены из свободного хранилища. Если этот вариант соответствует всем вашим критериям, я бы предложил перейти на shared_ptr<Student> вместо необработанные указатели.

person Christophe    schedule 30.03.2016
comment
1) Я не знаю окончательного количества элементов в структуре, но их тысячи. 2) Я мог бы попытаться сделать это таким образом, однако не гарантируется, что некоторые студенты не будут удалены (я бы сказал, что они будут удалены гарантированно....). Поэтому мне нужно найти способ, как снова проверить и отсортировать структуру. Идея заключалась в том, чтобы сохранить сортировку, чтобы можно было реализовать бинарный поиск. Мне нужно работать со значениями в структуре относительно быстро (макс. O (log n)). - person Filip N.; 31.03.2016
comment
Если вы инкапсулируете свою структуру данных в классе, вы вполне можете контролировать удаление и предусматривать вставку учащихся в порядке, отличном от последовательного. Использование индексов сделало бы это очень удобным для реализации, поскольку в отсортированных векторах вы могли бы легко найти индексы, которые нужно удалить, и индексы, которые нужно настроить. - person Christophe; 31.03.2016