2015-01-14 5 views
0

Я использую Qt 4.7.4 с MS Visual C++ 2010.QMap :: содержит() и QMap ::() значение не находит существующий ключ-значение пары

Я использую следующий QMap:

QMap<T_FileMapKey, HANDLE> m_oMapHistHandle; 

где T_FileMapKey определяется как:

typedef struct tagT_FileMapKey 
{ 
    int iSubscriptIdx; 
    int iFilterIdx_1; 
    int iFilterIdx_2; 
} T_FileMapKey; 

для того, чтобы получить все это происходит, я перегрузил < оператора:

bool operator< (const T_FileMapKey& tVal1, const T_FileMapKey& tVal2) 
{ 
    if(tVal1.iSubscriptIdx < tVal2.iSubscriptIdx) 
    { 
     return true; 
    } 
    else 
    { 
     if(tVal1.iFilterIdx_1 < tVal2.iFilterIdx_1) 
     { 
      return true; 
     } 
     else 
     { 
      if (tVal1.iFilterIdx_2 < tVal2.iFilterIdx_2) 
      { 
       return true; 
      } 
      else 
      { 
       return false; 
      } 
     } 
    } 
}; 

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

Моя проблема:

if (INVALID_HANDLE_VALUE == m_oMapCurrHandle.value(tFileKey, fdInvalidHandle)) 
.... 

и

if (false == m_oMapHistHandle.contains(tFileKey)) 
.... 

(где tFileKey переменная T_FileMapKey) не всегда возвращает правильное значение.

В нормальных условиях QMap растет с течением времени, что означает, что при обнаружении новой комбинации индексов файл открывается, и запись добавляется в QMap. Если я запускаю приложение в режиме отладки, надстройка Qt Visual Studio позволяет мне заглянуть в сохраненные пары значений ключа. Я вижу, что присутствует запись в Debug Watch (например, {0, 32767, 0}), но два вызова функций (содержит и значение) говорят мне, что QMap не имеет такого ключа. Обычно такое поведение встречается после того, как QMap имеет по крайней мере 15 пар ключ-значение.

Возможно, это ошибка в Qt 4.7.4? Что я делаю неправильно?

+0

Я удивлен, что отладочная версия Visual C++ не утверждают, что позволяет знать, точная причина ошибки.Предполагается, что время выполнения отладки VS вызовет ваш 'operator <' дважды для каждой итерации, где первый раз вызывает его с (a, b), а второй раз с (b, a) и проверяет возвращаемое значение каждого вызова. – PaulMcKenzie

ответ

3

Ваш operator< неправ. Чтобы объяснить, рассмотрим более простую причину для написания operator< только для pair<int, int>. Ваша версия реализована таким образом:

bool operator<(const pair<int, int>& lhs, const pair<int, int>& rhs) 
{ 
    if (lhs.first < rhs.first) { 
     return true; // (1) 
    } 
    else if (lhs.second < rhs.second) { 
     return true; // (2) 
    } 
    else { 
     return false; // (3) 
    } 
} 

Так {1,4} < {2,3} из (1). Но {2,3} < {1,4} по причине (2)! Таким образом, мы получаем operator<, который не устанавливает порядок.

Самый простой способ установить лексикографическое сравнение было бы полностью разобраться с каждым членом в свою очередь:

bool operator<(const pair<int, int>& lhs, const pair<int, int>& rhs) 
{ 
    if (lhs.first != rhs.first) { 
     return lhs.first < rhs.first; 
    } 
    else { 
     return lhs.second < rhs.second; 
    } 
} 

Та же идея может быть легко расширена на ваш тройной.

+0

Вы сэр одна из причин, я люблю переполнение стека! Большое спасибо, я действительно сделал глупую ошибку ... – tebe

0

Я думаю, ваша проблема в вашем меньшем операторе, потому что вы никогда не сравниваете его с большим знаком. Вы должны иметь что-то вроде этого:

bool operator< (const T_FileMapKey& tVal1, const T_FileMapKey& tVal2) 
{ 
    if(tVal1.iSubscriptIdx < tVal2.iSubscriptIdx) 
    { 
     return true; 
    } 
    else if (tVal2.iSubscriptIdx < tVal1.iSubscriptIdx) 
    { 
     return false ; 
    } 
    else 
    { 
     if(tVal1.iFilterIdx_1 < tVal2.iFilterIdx_1) 
     { 
      return true; 
     } 
     else if (tVal2.iFilterIdx_1 < tVal1.iFilterIdx_1) 
     { 
      return false ; 
     } 
     else 
     { 
      if (tVal1.iFilterIdx_2 < tVal2.iFilterIdx_2) 
      { 
       return true; 
      } 
      else 
      { 
       return false; 
      } 
     } 
    } 
}; 

я использовал только меньше оператора, потому что вы не можете иметь другие определенные