2012-03-09 4 views
2

Я расширяю уже существующий код на C++. Один из членов класса имеет тип вектора другого класса объектов:использовать карту вместо вектора

class Road 
{ 
    .... 
    vector<Link*> links; //Link is just another class 
} 

Остальные модули используют этот класс и его член через много итераторы последовательности. Теперь, расширяя код, мне нужно добавить элемент в класс Link, называемый linkID, и использовать этот идентификатор ссылки, чтобы найти/получить доступ к моим объектам «Ссылка».

Проблема: Я не собираюсь искать объект Link (используя LinkID) в векторе, итерации по миллионам элементов, чтобы найти конкретный объект Link. Лучшим решением является «карта»! правильно?

.... 
map<linkID,*link> links 
.... 
lnk=links[linkID] 
......... 

Но проблема в том, что я не могу изменить текущий исходный код, за исключением очень незначительных модификаций Лика добавления LinkId и т.д.

Так что мой очевидный вопрос: можно ли использовать карту вместо вектора (любой как). Другими словами, я хочу создать карту, заполнить ее и позже рассматривать ее как вектор. возможное? Благодарю вас за комментарии

+1

До тех пор, пока код, который у вас есть, реализован умно, т.е.: не полагаясь на случайное поведение итератора 'std :: vector', просто изменяя тип, должен делать трюк. В конечном итоге вам придется пересмотреть все случаи, когда вы полагайтесь на последовательный характер контейнера, но тогда вы не можете ему помочь, если существующий код полагается на это поведение, он плохо написан в первую очередь. –

+0

Я согласен с Als выше. Однако это больше, чем просто случайное поведение итератора. Например, код делает что-то вроде 'links.push_back (ptr)'? Кроме того, код, основанный на позиционном доступе к ссылкам? – Kaz

+0

@ KAZ FYI, linkID - строка, подобная «lnk001», поступающая из XML и используемая позже как ПК таблицы БД. – rahman

ответ

0

Лучшее решение - «карта»! правильно?

Да, звучит как карта, это самое простое решение вашей проблемы. Но вместо использования оператора [] я бы использовал методы поиска и вставки.

Первоначально, вы можете изменить код, чтобы использовать карту этого типа std::map< unsigned int, link* >, так как это самое похожее на vector< link* >. Затем вы можете легко переключиться на std::map< LinkId, link* >.

0

Скрыть карту как вектор невозможно.

В теории вы можете попытаться реализовать новый класс , полученный из вектора (т. Е. Использует std::vector в качестве базового класса). Внутри он мог использовать карту, а снаружи он имел бы интерфейс вектора (и он был бы принят в качестве замены вектора, потому что он был получен из него).

На практике у вас может возникнуть ряд проблем. Вы, очевидно, наследовали бы внутренние структуры данных вектора, так что вам пришлось бы игнорировать их в своей реализации, т. Е. Оставить их пустыми. Вывод из классов STL (кроме basic_) также противоречит рекомендуемой практике и, возможно, рискованному, как отмечает @Als в комментарии ниже.

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

+2

Контейнеры стандартной библиотеки не предназначены для использования в качестве базовых классов, у них нет виртуального деструктора. Так что это плохой совет. Если лучше всего использовать композицию, а не наследование при работе со стандартными библиотечными контейнерными классами. –

+0

@Als Да, но если вы просто замените вектор на карту, вам придется изменить большую часть исходного кода, например. потому что возврат карты итераторов полностью отличается от возвращаемых вектором. Это то, что OP хочет избежать (или избегать). – jogojapan

+0

@Als не было бы проблемой только в том случае, если у него был std :: vector * vp = new MyDerivedClass ? Частное наследство было бы безопасным (я не говорю, что это было бы правильным решением) – juanchopanza

0

Я думаю, что вы могли бы сделать, это сделать дополненную структуру данных: vectormap, которая позволяет иметь шпоночный доступ к элементам по linkID и который также поддерживает операции std::vector. Оператор [] этого объекта может быть перегружен, так что links[3] дает вам позиционный доступ к вектору, а links[linkID] просматривает ID ссылки на карте.Такие вещи, как push_back, могут поддерживаться, если код им нужен: push_back пришлось бы вставить элемент в вектор, а затем сделать map[item->linkID] = item, чтобы ввести его на карту. Вы, вероятно, получите картину.

+0

ничего себе! Я не могу понять, как, но я только начну давать ему попробовать и вернуться к вам позже. – rahman

0

Я сделал это много лет назад для сети железных дорог. Базовыми классами были ссылка и узел. Фактические железнодорожные и в конечном итоге маршруты были основаны на вершине этих. IIRC I использовал std::list, чтобы содержать ссылки и узлы и использовать векторы векторов для размещения фактических треков.

0

Правильное решение, если linkID является членом Link, будет std::set<Link*, OrderByLinkID>. Предикат OrderByLinkID принимает два Link* и возвращает true, если первый имеет меньший элемент linkID.

В результате std :: set по-прежнему содержит Link*, и вы можете перебирать их так же, как std :: vector. Для сравнения: с std :: map вы закончите повторение более std::pair<Link*, LinkID>, что значительно больше.

+0

Привет, надеюсь, вы все еще следуете этому. Мне нужно знать, как быстро будет поиск в вашем «установленном» решении? Основная причина, по которой я это делаю, - это возможность быстрого поиска Link (или любого другого объекта), будет ли это решение быстрее, чем карта? – rahman

+0

Оба являются «O (log N)». Вектор является «O (N)», в сравнении. – MSalters

Смежные вопросы