#c #stl
#c #stl
Вопрос:
Добрый день, я обнаружил, что std:multimap::equal_range
иногда возвращает неправильные результаты. Возможно ли это? Если да, есть ли обходной путь или какая-то ошибка в моем коде или хэш-функции для указателей. Спасибо.
Вот выдержка из моего кода:
typedef std::multimap<char *,Range>::const_iterator I;
std::pair<I,I> b = mmultimap.equal_range(TmpPrevMapPtr);
for (I i=b.first; i != b.second; i){
ranges_type.erase(i->second);
}
erasecount = mmultimap.erase(TmpPrevMapPtr);
где mmultimap имеет хэшированный ключ указателя и значение диапазона. Диапазон классов выглядит следующим образом:
class Range {
public:
explicit Range(int item){// [item,item]
mLow = item;
mHigh = item;
mPtr = 0;
mMapPtr = 0;
mStamp = 0;
}
Range(int low, int high, char* ptr = 0,char* mapptr, int stamp){
mLow = low;
mHigh = high;
mPtr = ptr;
mMapPtr = mapptr;
mStamp = stamp;
}
int low() const { return mLow; }
int high() const { return mHigh; }
char* getPtr() const { return mPtr; }
char* getMapPtr() const { return mMapPtr; }
int getStamp() const { return mStamp; }
private:
int mLow;
int mHigh;
char* mPtr;
char* mMapPtr;
int mStamp;
}; // class Range
Комментарии:
1. Какой у вас
char*
ключ? Это указатель на строку C или что-то еще? Вы действительно имеете в виду использовать здесь указатель? (То есть вы действительно хотите идентифицировать элементы по адресу конкретных экземпляров строк?) Вы уверены, что не хотите использоватьstd::string
или какой-либо другой класс string?2. @Джеймс Макнеллис, спасибо за ваш ответ, Вы правы в том, что char * key является указателем на строку C. В идеале я хотел бы использовать указатель на строку C. Я помню, как 5 лет назад я посещал урок информатики, где профессор Рони Хартун дал нам задание, в котором мы должны были построить хэш-карту с ключами, которые были указателями на строку C, я не использовал STL для решения этой программы. Вы хотите сказать, что в STL лучше не использовать указатели char * в качестве ключей к std:: multimap? Спасибо.
3. вы можете использовать
char*
в качестве ключей кstd::multimap
, если вы используете их правильно. Просто поймите, что операторы сравнения (в частности,<
иstd::less
) показывают, указывают ли они на идентичную строку, а не на строки с идентичным содержимым.4. Лучше избегать строк C, точка.
Ответ №1:
Вы сравниваете char*
указатели на равенство, когда хотите сравнить строки C. Вам нужно предоставить функтор сравнения для multimap или (еще лучше) использовать std::string . Рассмотрим следующую программу и обратите внимание, как A1
!= A2
, но strcmp(A1, A2)==0
.
#include <map>
#include <string>
#include <cstring>
#include <iostream>
struct compare {
bool operator()(char *left, char *right) const {
return std::strcmp(left,right) < 0;
}
};
int main() {
char A1[] = "A";
char A2[] = "A";
std::multimap<char*, int> bad;
bad.insert(std::pair<char*,int>(A1, 1));
bad.insert(std::pair<char*,int>(A2, 1));
std::cout << bad.count("A") << ", " << bad.count(A1) << "n";
std::multimap<char*, int, compare> good;
good.insert(std::pair<char*,int>(A1, 1));
good.insert(std::pair<char*,int>(A2, 1));
std::cout << good.count("A") << ", " << good.count(A1) << "n";
std::multimap<std::string, int> better;
better.insert(std::pair<std::string,int>(A1, 1));
better.insert(std::pair<std::string,int>(A2, 1));
std::cout << better.count("A") << ", " << better.count(A1) << "n";
}
Комментарии:
1. Спасибо за ответ. Я оставил строку кода в своем отрывке: UnmapViewOfFile(PrevMapPtr); TmpPrevMapPtr = PrevMapPtr;typedef std::multimap<char *,Range>::const_iterator I; std::pair<I, I> b = mmultimap.equal_range(TmpPrevMapPtr); для (I i= b .первый; i != b.второй; i){ ranges_type.erase(i-> второй); } erasecount = mmultimap.erase(tmpprevmappptr);
2. Спасибо за ответ. Я оставил строку кода в моем отрывке: 1. UnmapViewOfFile(PrevMapPtr); 2. TmpPrevMapPtr = PrevMapPtr; 3. typedef std::multimap<char *,Range>::const_iterator I; 4. std::pair<I, I> b = mmultimap.equal_range(TmpPrevMapPtr ); 5. для (I i=b.first; i != b.second; i){ ranges_type.erase(i-> второй); } 6. erasecount = mmultimap.erase(tmpprevmappptr); Поскольку UnMapOfViewOfFile делает недействительным указатель char *, мы не можем использовать strcmp, что нам следует делать? Спасибо.
3. Я не уверен в том, что вы говорите, и я не знаю, что
UnmapViewOfFile
делает, но я могу сказать следующее: ключи должны быть действительны в течение всего срока их существования на карте. Лучшее исправление: использоватьstd::string
в качестве типа ключа.4. Спасибо за ваш ответ. Я попробую это. UnmapViewOfFile «Отменяет отображение отображенного представления файла из адресного пространства вызывающего процесса». Мы создаем приложение для просмотра файлов с отображением в памяти. Я думаю, мы отложим отмену просмотра файла до тех пор, пока не вызовем std::multimap::equal_range . Спасибо.
Ответ №2:
Способ, которым вы используете итераторы, неверен. При использовании метода erase итератор стал недействительным. Ему должно быть переназначено возвращаемое методом erase значение.
Другими словами:
for (I i=b.first; i != b.second; i){
ranges_type.erase(i->second);
}
должно быть
I i = b.first;
while (i != b.second){
i = ranges_type.erase(i->second);
}