Когда структура данных является параметром шаблона, как я могу определить, приведет ли операция к недействительности итератора?

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

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

Но как я могу закодировать общий класс, который легко справляется с обоими случаями?

Если я могу узнать, приведет ли push_back к недействительности итератора, я могу сохранить итератор и обновить его после каждого push_back, сохранив расстояние от начала до операции.

Ответы

Ответ 1

Вероятно, вы должны избегать такой гибкости. Цитата из статьи 2 " Остерегайтесь иллюзии контейнеро-независимого кода" из Эффективный STL от Scott Meyers:

Посмотрите правде: это не стоит. Различные контейнеры разные, и у них есть сильные и слабые стороны, которые существенно различаются. Они не предназначены для взаимозаменяемости и там вы можете сделать это, чтобы закончить. Если вы попробуете, вы просто заманчивая судьба, и судьба не любит соблазняться.

Если вы действительно, безусловно, обязательно должны поддерживать действительные итераторы, используйте std::list. Если вам также нужен произвольный доступ, попробуйте Boost.MultiIndex (хотя вы потеряете непрерывный доступ к памяти).

Если вы посмотрите на стандартные адаптеры контейнеров (std::stack, std::queue), вы увидите, что они поддерживают пересечение интерфейсов адаптируемых контейнеров, а не их объединение.

Ответ 2

Я бы создал второй класс, ответственность за которого будет вернуть интересующий вас итератор. Он также должен быть параметризован с одним и тем же параметром шаблона, а затем вы можете специализировать его для любого типа, который вы хотите (вектор/список и т.д.). Таким образом, внутри вашей специализации вы можете использовать любой метод, который вы хотите.

Итак, это решение, основанное на чертах.

Ответ 3

Если вы действительно хотите придерживаться вектора и иметь эту функциональность, можете взглянуть на
http://en.cppreference.com/w/cpp/container/vector/capacity. оберните ваши push_backs в определенной функции или даже лучше оберните весь std::vector в ур-классе, и перед push_backing сравните емкость с size(), чтобы проверить, не изменится ли размер.