QMap ein Container mit vielen Fragezeichen.

Verschiedenes zu Qt
Antworten
cooky1976
Beiträge: 76
Registriert: 24. Januar 2008 00:19

QMap ein Container mit vielen Fragezeichen.

Beitrag von cooky1976 »

Hallo,

ich habe hier mehrere Probleme mit dem Container QMap. Die Trolltech-Doku habe ich hierzu auch schon mehrfach gewälzt.

Laut Doku hat ich ja:

Code: Alles auswählen

QMap<QString, QString> map;
map.insert("test", "test");
Ich möchte aber den Container an einem Funktionsaufruf übergeben und dann füllen und den befüllten Container am ursprünglichen Ort weiterverarbeiten (QMap wird vom QXmlStreamReader gefüllt und die Werte verarbeite ich in der Ausgangsklasse).

Sieht dann bei mir so aus:

Code: Alles auswählen

    QMap<QString, QString> values;
    ReadConfiguration *reader = new ReadConfiguration();
    reader->getValues(values);
Allerdings kann ich die QMap, was auch immer ich mache nicht mit Werten befüllen. Ich habe mir als Test in der Reader-Klasse ein lokales Qmap in der Headerklasse angelegt und veruche nun dieses zu füllen:

Code: Alles auswählen

            QString test = reader.name().toString();
            QString test3 = "simulatorname";
            
            if (reader.name() == "simulatorname") {
                QString test4 = reader.readElementText();
                tmp_values.insert(test, test4);
Eigentlich habe ich hier mit allen Mitteln versucht sicherzustellen, dass es 2 QStrings sind, aber bei Zugriff auf tmp_values.value("simulatorname") komme ich immer nur zu einer Fehlermeldung.

Jeglicher Input zu der referenziellen Übergabe von QMap und QHash und der insert-Problematik wird dankend angenommen :-)

Nachtrag: Es gibt ja den Konstruktor "QMap ( const QMap<Key, T> & other )". Wird der dann so eingesetzt:

Code: Alles auswählen

map = new QMap<Qstring, QString> ( map2 )
?
CLRS530
Beiträge: 155
Registriert: 8. Oktober 2007 18:00

Beitrag von CLRS530 »

Das ist für mich auch die größte Problematik und das größte Rätsel an Qt. Man arbeitet ständig mit Referenzen, Zeigern und was weiß ich und dabei verhalten sie sich aber teilweise anderes, als man es eigentlich von C++ erwartet (gerade Signals und Slots).

Aber jetzt zu deiner Situation. Du hast uns nicht den Funktionskopf von ReadConfiguration::getValues gegeben, was deutungen deines Fehlers erschwert. Aber wenn du dort QMap<QString, QString> value stehen hast, kann das nicht gehen.
QMap<QString, QString> &value müsste im Grunde gehen, ich bin mir da aber bei Qt gar nicht mehr so sicher.
Problemlos sollte aber auf alle Fälle folgendes gehen:

Code: Alles auswählen

ReadConfiguration::getValues(QMap<QString, QString> *values)
{
     values->insert("test", "test");
}
und dann natürlich

Code: Alles auswählen

QMap<QString, QString> values;
ReadConfiguration *reader = new ReadConfiguration(); 
reader->getValues(&values);
cooky1976
Beiträge: 76
Registriert: 24. Januar 2008 00:19

Beitrag von cooky1976 »

Danke, ja, Du hast recht, ich war mir nicht sicher, ob das bei den Containern auch mit Pointern klappt.
Allerdings sehe ich es nicht als Call-by-Reference, da die Ursprungsvariable unverändert ist. hat wahrscheinlich hiermit zu tun:
This operation occurs in constant time, because QMap is implicitly shared. This makes returning a QMap from a function very fast. If a shared instance is modified, it will be copied (copy-on-write), and this takes linear time.
Allerdings geht dies zum Verr.... nicht:

Code: Alles auswählen

#include <QMap>
#include <QString>

int main( int argc, char *argv[] )
{
    QMap<QString, QString> map;
    QString key1 = "key1";
    QString value1 = "value1";
	map.insert(key1, value1);

    return 0;
}
QT Version 4.5.0

Liegt das an mir? oder an QT?

Nach dem Insert sagt mir der Debugger, das Element ist nicht vorhanden. Bzw. s. Anhang.

Vielleicht können ja doch mal die Experten etwas dazu sagen, auch wenn das eventuell unter deren Niveau ist ....

Nach zahlreichen Tests sagt mir mein Gefühl, dass die Datensätze hinzugefügt werden, jedoch es Probleme im Debugger von VS gibt. Kann das jemand bestätigen?[/quote]
Dateianhänge
watchboard.png
watchboard.png (4.44 KiB) 8618 mal betrachtet
CLRS530
Beiträge: 155
Registriert: 8. Oktober 2007 18:00

Beitrag von CLRS530 »

Wieso bastelst du an so etwas rum und nicht dort, wo du es einsetzten willst. Ein debugger optimiert normalerweise soweit ich weiß gar nicht. Aber was du da machst ist überaus sinnfrei und das Objekt wird auch gar nicht benutzt.
iso8859-1
Beiträge: 25
Registriert: 8. März 2009 11:02

Beitrag von iso8859-1 »

This operation occurs in constant time, because QMap is implicitly shared. This makes returning a QMap from a function very fast. If a shared instance is modified, it will be copied (copy-on-write), and this takes linear time.
Das hier bedeutet blos, dass du eine QMap by value ohne Probleme zurückgeben kannst. Das bedeutet nicht, dass du eine lokale Variable zurückgeben kannst. Normalerweise wird eine lokale Variable in einer Funktion auf dem Stack angelegt und wieder freigegeben, sobald die Funktion verlassen wird (dieses Verhalten wird z.b. in RAII genutzt, ein gängiges C++ Pattern).

Was das ganze also meint: Du kannst eine QMap in einem Objekt by Value haben und auch aus dem Objekt by value zurückliefern

Code: Alles auswählen

class foo
{
private:
   QMap<QString, QString> map;
public:
   QMap<QString, QString> get() { return map; }
}
map kann hier zum lesen einfach zurückgegeben werden, da nichts kopiert wird, wenn allerdings in eine Kopie von map, die man mit get() erhalten hat, geschrieben wird, so wird dies nicht in map erscheinen.

Code: Alles auswählen

foo f;
QMap<QString, QString> m = f.get(); //enthält die selben einträge wie map in f
m.insert("test", "test"); //map in foo enthält nun NICHT den key test
                                 //die map wird hier kopiert. m enthält den key test.
wenn du das gleiche Spiel mit Referenzen oder Pointern machst, bleiben m und map aus f identisch.

Anmerkung: Referenzen sind sich selbst dereferenzierende Pointer die immer auf ein Objekt zeigen.
René
Beiträge: 75
Registriert: 15. August 2006 11:14
Kontaktdaten:

Beitrag von René »

cooky1976 hat geschrieben:QT Version 4.5.0

Liegt das an mir? oder an QT?

Nach dem Insert sagt mir der Debugger, das Element ist nicht vorhanden. Bzw. s. Anhang.

Vielleicht können ja doch mal die Experten etwas dazu sagen, auch wenn das eventuell unter deren Niveau ist ....

Nach zahlreichen Tests sagt mir mein Gefühl, dass die Datensätze hinzugefügt werden, jedoch es Probleme im Debugger von VS gibt. Kann das jemand bestätigen?
Kann ich bestätigen. Wenn man in Visual Studio einen Breakpoint setzt um sich einen QMap Container anzusehen, dann sieht man zwar, dass der QMap Container die richtige Anzahl an Key/Value-Paaren enthält, aber jeder Key wird nur mit "Error" angegeben, jeder Value ist immer vom Typ int mit Wert 0.

Ich habe den RC vom Visual Studio AddIn installiert, welcher auch erweiterte Debug-Symbole mitliefert, dennoch klappt das nicht für QMap. Eventuell sind noch andere Container Klassen betroffen.
cooky1976
Beiträge: 76
Registriert: 24. Januar 2008 00:19

Beitrag von cooky1976 »

CLRS530 hat geschrieben:Wieso bastelst du an so etwas rum und nicht dort, wo du es einsetzten willst. Ein debugger optimiert normalerweise soweit ich weiß gar nicht. Aber was du da machst ist überaus sinnfrei und das Objekt wird auch gar nicht benutzt.
Ich kann mir doch gerade einen Kommentar einfach nicht verkneifen.
Über Sinn oder Unsinn solltest Du Dir eventuell nicht den Kopf zerbrechen. Es macht durchaus Sinn, da es ein Testprogramm ist und ein Testprogramm nur die minimalsten Anforderungen erfüllen sollte. Dies ist in meinem Fall eine QMap zu initiieren und einen Breakpoint zu setzen und ein paar Werte einzutragen. Das macht es und damit Sinn.

Es tut mir leid, dass ich nicht das vollkommene Programm gepastet habe, ich werde es nächstes Mal anhängen :wink:
Troll.Soft
Beiträge: 190
Registriert: 18. Juni 2008 09:52
Wohnort: Hamburg

Tipp zu Qt-Container

Beitrag von Troll.Soft »

Hallo,
möchte hier mal einen kleinen Tip zum Umgang mit Qt-Containern beisteuern. Benutzt typedef und der Umgang mit Containern ist ganz easy. Gilt natürlich auch für Container von STL, Boost etc.

typedef QMap <QString, QString> myMap;

anschließend nur noch myMap map und die Map ist brauchbar.

myMap map;
QString s1, s2;
function(myMap map) { map[s1] = s2; ... }
function(myMap& map) { map[s1] = s2; ... }
function(myMap* map) { map[s1] = s2; ... }

auch so etwas klappt wunderbar.

myMap function()
{
myMap map;
map[s1] = s2;
return map;
}

funktioniert alles so wie man es sich mit normalen skalaren Parametern vorstellt.
cooky1976
Beiträge: 76
Registriert: 24. Januar 2008 00:19

Beitrag von cooky1976 »

Ich persönlich bin nicht wirklich ein Fan von Typedefs bei Containern. Meines Erachtens geht dabei einfach viel zu viel Information verloren. Noch dazu, wenn das Programm ein paar Zeilen lang wird. Ich hatte das gerade eben ...
da wurde ein unsingnd long gealiast als ULong, der ULong als Handle, das Handle als ObjectHandle *wenn es nicht noch ein Schritt mehr war*.

Bis man da mal weiß, was es denn für ein Grundtyp ist, läuft einiges an Wasser die Donau entlang. Und es gibt hin und wieder Situationen, da brauvht man für Konvertierungen einfach den Basistyp.

*ist aber nur meine persönliche Meinung*
RHBaum
Beiträge: 1436
Registriert: 17. Juni 2005 09:58

Beitrag von RHBaum »

Ich persönlich bin nicht wirklich ein Fan von Typedefs bei Containern.
typdefs machen sinn, wenn:
a: man datentypen an zentraler stelle pflegen will, also man schnell mal eben nen datentyp durch nen anderen kompatiblen datentyp ersetzen will ...
b: sich beim schreiben von typen ned die finger brechen will !!!

Denk mal grad im Umgang mit maps und anderen Templates ist Punkt b durchaus gegeben ...
Arbeit mal viel mit iteratoren und und weitern abhangigen Subtypen, dann iss std::map<int,int>::const_iterator zu MapT::const_iterator scho ne arge vereinfachung. Und das blaeht sich oft noch viel mehr auf ... hab mal als Key nen pair oder sowas ^^

Mann sollt natuerlich die Namen der typdefs auch irgendwie sinnig waehlen !
QMap<QString, QString> &value müsste im Grunde gehen, ich bin mir da aber bei Qt gar nicht mehr so sicher.
Warum nicht ???
Das impliziete sharen entbindet dich nicht von der logic, die du selber implementieren musst. Die referenz an der stelle ist der einzig richtige Weg !

Was passiert beim implizierten sharen ?

Code: Alles auswählen

reader->getValues(values); 
von values wird eine Kopie erzeugt, sprich ein neues object aufn stack aungelegt, desen (dynamische)daten aber auf die gleichen Daten wie bei value zeigen (shared), oder NULL, wenn in value eh nix drinne stand ....
in der funktion selber beschreibst aber das object ... sprich sobald du schon einen nichtkonstanten zugriff wie [] oder so auf das object macht, wird es geteilt, sprich spaetestens hier wird die kopie gemacht, und dein object und value zeigen nimmer auf die selben daten ....

Lass dich ned verwirren, an der Logic aendert sich nix durch das impliziete sharen ...

Probleme mit implizien sharen bekommst du generell nur, wenn dich indirekt intressiert, wo die daten liegen.
Das ist bei folgenden Themen der fall:

Du gibst konstante Pointer auf beinhaltende daten raus:
bei implizieten sharen , und beim aufloesen des shares weisst du nicht, welches stack-object den zeiger auf das neukopierte bekommt, und welches die ursprünglichen daten behaelt. das heisst schlimmstenfalls, machst du nen schreiboperation auf das andere Object mit dem daten sharest, und bei dir aendert sich intern der pointer auf die daten, was du aber gar ned mitbekommst

Laufzeitverhalten:
Du weisst nimmer genau, wann wirklich kopiert wird. Oftmals verlagert man kopieroperationen bewusst an zeitpunkte, wo es nicht weh tut ... das impliziete sharen kann dir dass unmöglich machen ....

multithreading generell:
du musst daten schuetzen damit sich schreib und lesezugriffe ned in die quere kommen. Aber wie, wenn du selbst ned entscheidest, bzw weisst, wann ne kopie gemacht wird und wann ned.

Fazit:
Wenn obige Themen anstehen, meide impliziet shared Objecte.
Bei der QT ist dies nur fuer alle nicht QObject abgeleiteten klassen relevant. Also meistens Container (untypisiert wie QMap, typisiert wie QString, QPixmap) .... nimm die stl und rohdaten fuer.
Alles was mit QObject zu tun hat, weisst du eh nie wanns geloescht wird ... und sind meistens GUI relevant, also dürfen per definition im Hauptthread verwendet werden.

fuer 90% der User wird dass aber nie der Fall sein. Man sollt nur wissen, wann es zu Problemen kommen kann ...

Ciao ...
000Hunter000
Beiträge: 8
Registriert: 23. November 2006 01:15

Beitrag von 000Hunter000 »

Hi,
RHBaum hat geschrieben:[
multithreading generell:
du musst daten schuetzen damit sich schreib und lesezugriffe ned in die quere kommen. Aber wie, wenn du selbst ned entscheidest, bzw weisst, wann ne kopie gemacht wird und wann ned.
wie kommst du darauf? Trolltech hat doch extra soviel aufwand betrieben z.B. mit atomaren Operationen gerade damit implecit sharing und Threads funktionieren. Natürlich kann man auch z.B. eine QMap an einen andren Thread übergeben da passiert nix schlimmes (falls man der Qt Dokumentation trauen kann :) )
000Hunter000
Beiträge: 8
Registriert: 23. November 2006 01:15

Beitrag von 000Hunter000 »

Noch was:
RHBaum hat geschrieben: Du gibst konstante Pointer auf beinhaltende daten raus:
bei implizieten sharen , und beim aufloesen des shares weisst du nicht, welches stack-object den zeiger auf das neukopierte bekommt, und welches die ursprünglichen daten behaelt. das heisst schlimmstenfalls, machst du nen schreiboperation auf das andere Object mit dem daten sharest, und bei dir aendert sich intern der pointer auf die daten, was du aber gar ned mitbekommst
EIgentlich geht das auch ohne Probleme. Z.B. QVector führt bei einem Aufruf von data() (die nicht const Variante) ein detach(); aus somit ist die sache auch gegessen ;)
Troll.Soft
Beiträge: 190
Registriert: 18. Juni 2008 09:52
Wohnort: Hamburg

Beitrag von Troll.Soft »

wie kommst du darauf? Trolltech hat doch extra soviel aufwand betrieben z.B. mit atomaren Operationen gerade damit implecit sharing und Threads funktionieren. Natürlich kann man auch z.B. eine QMap an einen andren Thread übergeben da passiert nix schlimmes (falls man der Qt Dokumentation trauen kann :) )
Da kann ich noch zu einem ähnlichen Thema Erfahrungswerte beisteuern. Habe vor Jahren nur Container aus der STL benutzt. Alles bestens. Habe mein Project in dll's aufgeteilt. Nur noch Abstürze. Alles deutete auf die Container als Ursache hin. Googeln ergab: STL-Container vertragen den Übergang von einer dll zur anderen nicht. Bin komplett auf Qt-Container umgestiegen und alles in Butter.

tschüß
der TrollSoft
Antworten