QMap of QMaps

Alles rund um die Programmierung mit Qt
Antworten
conan2011
Beiträge: 15
Registriert: 18. Januar 2010 10:21

QMap of QMaps

Beitrag von conan2011 »

Ich bin eben so ratlos, wie dieses Thema bereits durchgekaut ist, bitte helft mir :-)

Ich will eine QMap füllen, die eine weitere QMap enthält.
Folgender Code funktioniert (index sei gegeben):

Code: Alles auswählen

QMap<QModelIndex, QMap <int,QVariant> > myBuffer;
QMap <int, QVariant> newEntry;
    newEntry.insert(1, QVariant("foo"));
    myBuffer.insert(index, newEntry);
sobald ich jedoch die Definition von myBuffer in den Header der Klasse verfrachte (private), meldet der Compiler folgenden Fehler:

Code: Alles auswählen

passing 'const QMap<QModelIndex, QMap <int, QVariant> >' as 'this' argument of 'QMap<Key, T>::iterator QMap<Key, T>::insert(const Key&, const T&) [with Key = QModelIndex, T = QMap<int, QVariant>]' discards qualifiers
die Definition von myBuffer MUSS aber in den Header, hat jemand eine Lösung?
Und wie kommt der Compiler überhaupt auf "const QMap...", ich hab doch nirgends "const" geschrieben :shock:
Never argue with an idiot,
he drags you down to his level,
and beats you with experience!
brax
Beiträge: 208
Registriert: 11. Mai 2010 11:22

Re: QMap of QMaps

Beitrag von brax »

conan2011 hat geschrieben: Und wie kommt der Compiler überhaupt auf "const QMap...", ich hab doch nirgends "const" geschrieben :shock:
Bist Du Dir da sicher? Grundsätzlich fehlt hier relevanter Code. Also die Klassendefinition und die Methode aus der der von Dir gepostete Code stammt.

Hier etwas, was kompiliert:

mapTest.h:

Code: Alles auswählen

#ifndef MAP_TEST_H
#define MAP_TEST_H

#include <QMap>
#include <QModelIndex>

class MapTest {

public:
	void insertTest(QModelIndex index);

private:
	QMap<QModelIndex, QMap <int,QVariant> > myBuffer;

};
#endif
Und die mapTest.cpp:

Code: Alles auswählen

#include "mapTest.h"

//-----------------------------------------------------------------------------
void MapTest::insertTest(QModelIndex index) {
	QMap<int, QVariant> newEntry;
	newEntry.insert(1, QVariant("foo"));
	myBuffer.insert(index, newEntry);
}
Das gibt keinen Fehler, also scheinst Du doch irgendwo etwas Code zu haben, den Du nicht gepostet hast und der dafür sorgt, dass es bei Dir einen Fehler gibt (meine Vermutung: Die Methode, die ich "insertTest" genannt habe, ist bei Dir const?)
conan2011
Beiträge: 15
Registriert: 18. Januar 2010 10:21

Re: QMap of QMaps

Beitrag von conan2011 »

Vielen Dank für die Mühe, die du dir gemacht hast.
Und du hast Recht, der Code steht in der data-Funktion meines QAbstractItemModels, und die ist 'const':

Code: Alles auswählen

QVariant myModel::data(const QModelIndex &index, int role) const
Das heißt es ist schier unmöglich, aus der "data() const"-Funktion heraus meine Klassenvariable zu verändern. Hmmm, 'const' einfach weglassen geht natürlich auch nicht.

Ich MUSS aber in der data-Funktion irgendwie meinen Buffer füllen.

Vielleicht hier noch eine Idee?
Never argue with an idiot,
he drags you down to his level,
and beats you with experience!
brax
Beiträge: 208
Registriert: 11. Mai 2010 11:22

Re: QMap of QMaps

Beitrag von brax »

Was Du Dich wohl fragen solltest ist, warum ist die data Methode const? Und (die eigentliche Frage), warum soll in der als const deklarierten Methode das this Objekt verändert werden (was Du ja tun möchtest, indem Du myBuffer verändern möchtest)? Grundsätzlich ist ja die Deklaration als const ein Hinweis, dass in dieser Methode das Objekt nicht verändert wird.

Die Antwort wird wohl lauten: weil Du eine Methode überschreibst, die const ist, richtig? Ich bin mir nicht sicher wie Dein Anwendungsfall ist, aber ich interpretiere das jetzt mal so, dass myBuffer quasi ein Cache ist. Nun könnte man argumentieren, dass durch die Änderung eines Caches die wesentlichen Eigenschaften Deines Objektes nicht wirklich verändert werden, wodurch ein Bruch der const-correctness zu vertreten wäre (man müsste dann natürlich sicher stellen, dass dieser "Cache" entsprechend invalidiert wird etc.). So richtig schön sauber ist es aber auf jeden Fall nicht, und manch einer würde Dir ganz doll auf die Finder hauen, wenn Du const-correctness ignorierst (mehr Informationen zu const-correctness und ein paar Gedanken, warum es eine feine Sache ist, darauf zu achten, findest Du hier: http://www.parashift.com/c++-faq-lite/c ... tness.html).

So oder so, es gibt nun zwei wege, wie Du trotz des const-qualifiers der data Methode Deinen Buffer verändern kannst:

1. const_cast

Code: Alles auswählen

QVariant myModel::data(const QModelIndex &index, int role) const {
   myModel* mutableThis = const_cast<myModel*>(this); // macht aus const myModel* ein myModel*
   mutableThis->myBuffer->insert(....);
....
}
2. myBuffer mutable deklarieren.

Code: Alles auswählen

class myModel : public QAbstractItemModel {
...
private:
   mutable QMap<QModelIndex, QMap <int,QVariant> > myBuffer; // das Schlüsselwort "mutable" bedeutet, dass dieser Member auch in const-Methoden verändert werden darf
};
Wie gesagt, die feine englische Art ist beides nicht gerade...
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Re: QMap of QMaps

Beitrag von franzf »

Wieso willst du einen Buffer in der data()-Methode FÜLLEN? data() wird recht oft aufgerufen. Wenn du anfängst, da groß rumzupuffern, kann das ziemlich auf die Performance gehen.
Wenn du dir aber wirklich sicher bist, gibt es zwei Möglichkeiten:
1) const_cast
2) mutable
Ich überlass es dir, wobei das mutable-keyword genau für solche Sachen existiert.
conan2011
Beiträge: 15
Registriert: 18. Januar 2010 10:21

Re: QMap of QMaps

Beitrag von conan2011 »

Perfekt, es funktioniert, ihr glaubt gar nicht wie dankbar ich bin!
mutable und const_cast kannte ich gar nicht, und wieder was gelernt.

Und auf die Frage, WARUM ich das überhaupt vorhabe:
Die data-Funktion holt in meiner Implementation jeden Wert über eine ODBC-Connection aus der Datenbank. Bislang ging das auch ausreichend flott, aber wenn die QTableView dann etwas größer wird, und für jedes einzelne Feld Daten mit mehreren roles abgefragt werden, geht die Performance ziemlich runter.
Aufgefallen ist mir das, als ich mit einem eigenen Contextmenü auf das Ereignis CustomContextMenuRequestet reagiert habe. Hier fordert die View nämlich nochmal ALLE Daten für absolut JEDES Feld der Tableview an.
Ich weiß, ich habe hiermit das eigentilche Problem umgangen, nämlich das ContextMenü daran zu hindern, einen kompletten Refresh der View anzuleiern, aber die Daten optional buffern zu können steht eh auf der ToDo-Liste.

Also, nochmal Vielen Dank!
Never argue with an idiot,
he drags you down to his level,
and beats you with experience!
Antworten