Open Source & Linux Lab

It's better when it's simple

User Tools

Site Tools


etc:blog:q_multi_hash_map_qsharedpointer

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
Last revisionBoth sides next revision
etc:blog:q_multi_hash_map_qsharedpointer [2011/01/27 18:40] voodetc:blog:q_multi_hash_map_qsharedpointer [2011/01/27 21:14] vood
Line 1: Line 1:
 ====== QMultiMap+QSharedPointer ====== ====== QMultiMap+QSharedPointer ======
 +
 +
  
 ==== Введение ==== ==== Введение ====
-Библиотека Qt предоставляет множество удобных средств для разработки любых приложений, например api для взаимодействия с мобильными платформами или набор классов для GUI приложений. Сложно представить себе крупное приложение написанное без использования стандартных контейнеров (векторов, деревьев). +Библиотека Qt предоставляет множество удобных средств для разработки приложений, например api для взаимодействия с мобильными платформами или набор классов для GUI программ. В данной статье речь пойдет об одной не совсем очевидной особенности совместного использования таких классов как QMultiMap и QSharedPointer. В качестве среды используется Ubuntu 10.04 с установленным Qt 4.6 . 
-В данной статье речь пойдет об одной не совсем очевидной особенности совместного использования таких классов как QMultiMap/QMultiHash и QSharedPointer.+ 
  
  
Line 12: Line 15:
 ==== Проблема ==== ==== Проблема ====
  
-Рассмотрим небольшой пример, который наглядно демонстрирует специфику совместного использования QMultiMap и QSharedPointer .+Впервые с данной проблемой я столкнулся, когда попробовал скомпилировать код, написанный для Qt 4.7, с использованием Qt 4.6. Часть незначительных ошибок удалось решить, исключив использование функций, появившихся в новой версии Qt. Однако одна ошибка казалась очень загадочной.  
 +<code bash> 
 + In file included from /usr/include/qt4/QtCore/qsharedpointer.h:52, 
 + from /usr/include/qt4/QtCore/QSharedPointer:1, 
 + /usr/include/qt4/QtCore/qsharedpointer_impl.h: In constructor 'QtSharedPointer::ExternalRefCount<T>::ExternalRefCount(const QtSharedPointer::ExternalRefCount<X>&) [with X = Channel, T = DataMark]': 
 + /usr/include/qt4/QtCore/qsharedpointer_impl.h:461: instantiated from 'QSharedPointer<T>::QSharedPointer(const QSharedPointer<X>&) [with X = Channel, T = DataMark]' 
 + /usr/include/qt4/QtCore/qmap.h:782: instantiated from 'QList<T> QMap<Key, T>::uniqueKeys() const [with Key = QSharedPointer<Channel>, T = QSharedPointer<DataMark>]' 
 + src/RSSFeedJSON.cpp:129: instantiated from here 
 + /usr/include/qt4/QtCore/qsharedpointer_impl.h:378: error: no matching function for call to 'QtSharedPointer::Basic<DataMark>::Basic(Channel* const&)' 
 + /usr/include/qt4/QtCore/qsharedpointer_impl.h:150: note: candidates are: QtSharedPointer::Basic<T>::Basic(Qt::Initialization) [with T = DataMark] 
 + /usr/include/qt4/QtCore/qsharedpointer_impl.h:149: note: QtSharedPointer::Basic<T>::Basic(T*) [with T = DataMark] 
 + /usr/include/qt4/QtCore/qsharedpointer_impl.h:123: note: QtSharedPointer::Basic<DataMark>::Basic(const QtSharedPointer::Basic<DataMark>&
 +</code>   
 +Больше всех настораживало сообщение  
 +<code bash> 
 + /usr/include/qt4/QtCore/qmap.h:782: instantiated from 'QList<T> QMap<Key, T>::uniqueKeys() const [with Key = QSharedPointer<Channel>, T = QSharedPointer<DataMark>]' 
 +</code> 
 +так как сигнатура функиции uniqueKeys должна выглядеть иначе.
  
-<code text>+Дальнейшие изыскания позволили выяснить, что проблема заключалась в использовании QMultiMap, у которого в качестве типа для ключевых значений был использован тип  QSharedPointer<...>
 + 
 +Рассмотрим небольшой пример, который наглядно демонстрирует специфику совместного использования QMultiMap и QSharedPointer в Qt 4.6. 
 +<code c++>
 #include <QSharedPointer> #include <QSharedPointer>
 #include <QMultiMap> #include <QMultiMap>
Line 21: Line 44:
  
 int main(int argc,char** argv){ int main(int argc,char** argv){
-        QMultiMap<QSharedPointer<int>, int> map; +        QMultiMap<QSharedPointer<int>, QString> map; 
-        int a=1,b=2+        inta,*b
-        QSharedPointer<int> aa(&a); +        a=new int; 
-        QSharedPointer<int> bb(&b); +        b=new int
-        map.insert(aa,1); +        QSharedPointer<int> aa(a); 
-        map.insert(bb,2); +        QSharedPointer<int> bb(b); 
-        map.insert(bb,3);+        map.insert(aa,"q"); 
 +        map.insert(bb,"qq"); 
 +        map.insert(bb,"qqq");
         QList<QSharedPointer<int> > unq=map.uniqueKeys();         QList<QSharedPointer<int> > unq=map.uniqueKeys();
-        printf("Unique keys:\n"); 
         return 0;         return 0;
 }</code> }</code>
  
-Если мы попытаемся скомпилировать данный пример с использованием qt версии 4.6, то получим следующие ошибки:+Если мы попытаемся скомпилировать данный пример, то получим следующие ошибки:
  
-<code text>+<code bash>
 In file included from /usr/include/qt4/QtCore/QMultiMap:1, In file included from /usr/include/qt4/QtCore/QMultiMap:1,
                  from main.cpp:2:                  from main.cpp:2:
-/usr/include/qt4/QtCore/qmap.h: In member function QList<T> QMap<Key, T>::uniqueKeys() const [with Key = QSharedPointer<int>, T = int]+/usr/include/qt4/QtCore/qmap.h: In member function 'QList<T> QMap<Key, T>::uniqueKeys() const [with Key = QSharedPointer<int>, T = QString]'
-main.cpp:18:   instantiated from here +main.cpp:23:   instantiated from here 
-/usr/include/qt4/QtCore/qmap.h:782: error: no match for operator<’ in aKey < i.QMap<Key, T>::const_iterator::key [with Key = QSharedPointer<int>, T = int]()+/usr/include/qt4/QtCore/qmap.h:782: error: no match for 'operator<in 'aKey < i.QMap<Key, T>::const_iterator::key [with Key = QSharedPointer<int>, T = QString]()'
 /usr/include/qt4/QtCore/qchar.h:385: note: candidates are: bool operator<(QChar, QChar) /usr/include/qt4/QtCore/qchar.h:385: note: candidates are: bool operator<(QChar, QChar)
 /usr/include/qt4/QtCore/qbytearray.h:520: note:                 bool operator<(const QByteArray&, const QByteArray&) /usr/include/qt4/QtCore/qbytearray.h:520: note:                 bool operator<(const QByteArray&, const QByteArray&)
Line 49: Line 73:
 /usr/include/qt4/QtCore/qstring.h:953: note:                 bool operator<(const QLatin1String&, const QLatin1String&) /usr/include/qt4/QtCore/qstring.h:953: note:                 bool operator<(const QLatin1String&, const QLatin1String&)
 /usr/include/qt4/QtCore/qstring.h:1181: note:                 bool operator<(const QStringRef&, const QStringRef&) /usr/include/qt4/QtCore/qstring.h:1181: note:                 bool operator<(const QStringRef&, const QStringRef&)
-/usr/include/qt4/QtCore/qmap.h: In function bool qMapLessThanKey(const Key&, const Key&) [with Key = QSharedPointer<int>]+/usr/include/qt4/QtCore/qmap.h: In function 'bool qMapLessThanKey(const Key&, const Key&) [with Key = QSharedPointer<int>]'
-/usr/include/qt4/QtCore/qmap.h:760:   instantiated from QMapData::Node* QMap<Key, T>::mutableFindNode(QMapData::Node**, const Key&) const [with Key = QSharedPointer<int>, T = int] +/usr/include/qt4/QtCore/qmap.h:760:   instantiated from 'QMapData::Node* QMap<Key, T>::mutableFindNode(QMapData::Node**, const Key&) const [with Key = QSharedPointer<int>, T = QString]' 
-/usr/include/qt4/QtCore/qmap.h:576:   instantiated from QMap<Key, T>::iterator QMap<Key, T>::insertMulti(const Key&, const T&) [with Key = QSharedPointer<int>, T = int] +/usr/include/qt4/QtCore/qmap.h:576:   instantiated from 'QMap<Key, T>::iterator QMap<Key, T>::insertMulti(const Key&, const T&) [with Key = QSharedPointer<int>, T = QString]' 
-/usr/include/qt4/QtCore/qmap.h:953:   instantiated from typename QMap<Key, T>::iterator QMultiMap<Key, T>::insert(const Key&, const T&) [with Key = QSharedPointer<int>, T = int] +/usr/include/qt4/QtCore/qmap.h:953:   instantiated from 'typename QMap<Key, T>::iterator QMultiMap<Key, T>::insert(const Key&, const T&) [with Key = QSharedPointer<int>, T = QString]' 
-main.cpp:15:   instantiated from here +main.cpp:20:   instantiated from here 
-/usr/include/qt4/QtCore/qmap.h:107: error: no match for operator<’ in key1 < key2+/usr/include/qt4/QtCore/qmap.h:107: error: no match for 'operator<in 'key1 < key2'
 /usr/include/qt4/QtCore/qchar.h:385: note: candidates are: bool operator<(QChar, QChar) /usr/include/qt4/QtCore/qchar.h:385: note: candidates are: bool operator<(QChar, QChar)
 /usr/include/qt4/QtCore/qbytearray.h:520: note:                 bool operator<(const QByteArray&, const QByteArray&) /usr/include/qt4/QtCore/qbytearray.h:520: note:                 bool operator<(const QByteArray&, const QByteArray&)
Line 72: Line 96:
 из-за которой и происходит сбой компиляции. Вот так выглядит ее прототип в документации Qt [[http://doc.qt.nokia.com/4.6/qmap.html#uniqueKeys|uniqueKeys]] : из-за которой и происходит сбой компиляции. Вот так выглядит ее прототип в документации Qt [[http://doc.qt.nokia.com/4.6/qmap.html#uniqueKeys|uniqueKeys]] :
 <code text>QList<Key> QMap::uniqueKeys () const</code> <code text>QList<Key> QMap::uniqueKeys () const</code>
-Очевидно, что возвращаемые значения в обоих случаях не совпадают.+Очевидно, что возвращаемые значения в обоих случаях не совпадают и нам удалось повторить ошибку на более простом примере. \\ 
 +Обратимся к описанию данной функции. Исходя из документации она возвращает список всех ключей в QMultiMap в порядке возрастания. Логично предположить, что основная проблема заключается в сортировке полученного списка ключей, ввиду отсутствия оператора сравнения определенного для типа QSharedPointer<T>.  
 +Определим свой оператор сравнения следующим образом: 
 +<code c++> 
 +template <class T> 
 +bool operator <(const  QSharedPointer<T>& a, const  QSharedPointer<T>& b){ 
 +        return a.data()<b.data(); 
 +
 +</code> 
 +Если включить код данного оператора в код примера, то компиляция пройдет нормально и мы получим работающее приложение. 
 + 
 +Проблема, похожая на описанную выше, возникает при замене QMultiMap на QMultiHash в примере. Для нормальной компиляции в таком случае необходимо определить собственную функцию qHash со следующим прототипом: 
 +<code c++> 
 +template <class T> 
 +uint qHash(const QSharedPointer<T>& a); 
 +</code> 
 + 
 + 
 +==== Заключение ==== 
 +Очевидно, что перегрузка оператора "<" для типа QSharedPointer<T> также следует и из сообщений компилятора. А это показывает, что написание простого примера ошибки в большом приложении позволяет весьма тривиальным образом найти ее причины. 
 +Описанная проблема устранена в новой версии Qt 4.7, которая входит в состав Qt SDK 1.1. Однако предложенное здесь решение остается актуальным, так как на момент написания статьи в OVI находится  Qt 4.6.
  
 {{tag>}} {{tag>}}
etc/blog/q_multi_hash_map_qsharedpointer.txt · Last modified: 2011/01/27 21:30 by kkv