Когда я это сделал, я использовал хеш-таблицу для символов, а не для сущностей.
Для каждого символа у меня был список сущностей. Каждая сущность была в двух
списки, один из символа, а второй из области видимости. Список
из символа управлялся как стек: когда я получил доступ к символу,
сущность по объему всегда была первой в списке. Когда я оставил прицел,
Я прошел его список объектов и удалил их из списка
символы.
Это было некоторое время назад, до STL (и даже до C ++); я
реализовал все вручную, и использовал инвазивные цепочки для
списки, с алгоритмом, разработанным так, чтобы я мог удалить элемент
из списка, не зная, где сам список был. (Это
относительно легко с рукописными двойными связанными списками.) Сегодня, с
STL (и с учетом важности локального доступа), я бы, вероятно, просто
поставить указатель на заголовок списка в каждой сущности. С STL и
учитывая местность, я бы, вероятно, использовал std::vector
для списка
для каждого объекта (таблица символов, таким образом, представляет собой карту std::string
в
std::vector
). Поиск таблицы символов, когда запись найдена, просто
вызов back()
для вектора (после проверки, что он не пустой, если
Вы не удаляете запись, когда вектор становится пустым). Когда ты
создать новую сущность, в новой области, вы вызываете push_back
на вектор,
и сохраните адрес вектора в записи для области (
std::stack
из std::vector<std::vector<Entity>*>
); при выходе
область, вы перебираете вектор в верхней части этого стека, вызывая
pop_back
на всех его записях, затем вытолкните его из стека. (А также
очевидно, при входе в новую область вы push
новый пустой вектор на
стек области действия.)
Ведение двойного списка означает, что для всех операций вы знаете,
какой именно элемент для доступа, без необходимости перебирать
что-нибудь; нет доступа к объекту, чтобы узнать,
ты ищешь. В мои дни это было довольно просто, но много
кода, требующего значительного ухода, и моя реализация, вероятно,
не будет так быстро сегодня из-за плохой местности. Сегодня с
STL, вам нужно гораздо меньше кода, и с помощью std::vector
для всех
списки, вы получаете немного лучшую местность; Вы все еще должны быть осторожны,
чтобы вы не сохранили итераторы, которые будут признаны недействительными.
(Но реализовано, как описано выше, вам не нужно; все обращения
всегда до последнего элемента вектора, поэтому сохранение адреса
самого вектора достаточно. При условии, конечно, что ваш хеш
реализация не перемещает векторы.)