Возможно ли, чтобы std:: multimap::equal_range возвращал неправильные результаты?

#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);
}