Когда структура данных является параметром шаблона, как я могу определить, приведет ли операция к недействительности итератора?
В частности, у меня есть класс, который в настоящее время использует вектор и 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(), чтобы проверить, не изменится ли размер.