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

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

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

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

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

15

Решение

Вы, вероятно, должны попытаться избежать этой гибкости. Цитата из пункта 2 «Остерегайтесь иллюзии контейнерно-независимого кода» от Эффективный STL Скотт Мейерс:

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

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

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

4

Другие решения

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

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

2

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

1
По вопросам рекламы [email protected]