Seite 1 von 1

[gelöst] const-Methoden und Zugriff auf QMap

Verfasst: 14. September 2009 10:06
von roeseb
Hallo zusammen,

ich grübel hier schon ziemlich lange an einem Problem und komm nicht drauf wieso der Compiler sich so verhält.

Ich habe einmal folgende Klasse geschrieben um mein Problem einfach nachvollziehen zu können:

Code: Alles auswählen

class c {
public:
    const QString* getPointer(const int &key) const { return &my[key]; }
    const QString* getPointer(const int &key)          { return &my[key]; }

private:
   QMap<int, QString> my;
};
Der Compiler bringt bei der ersten Methode die Warnung

"taking address of temoprary"

bei der zweiten jedoch nicht.

In meinem Programm hab ich das Problem bisher so umgangen, dass ich die betroffenen Methoden nicht als "const" deklariert habe. Jetzt bin ich aber einem Punkt, an dem sie eigentlich unbedingt const sein sollten, dafür will ich aber nicht immer eine Kopie des Objekts, das in der Map verwaltet wird, erzeugen müssen.

Viele Grüße und herzlichen Dank im Voraus!
Sebastian

Verfasst: 14. September 2009 10:14
von Christian81
Er verhält sich so weil die Qt-Funktionen so definiert sind: http://doc.trolltech.com/4.4/qmap.html#operator-5b-5d

Verfasst: 14. September 2009 12:36
von roeseb
Hallo Christian,

vielen Dank für die rasche Antwort. Ich hab mal wieder den Wald vor lauter Bäumen nicht gesehen. Dann hilft es wohl nichts und ich muss bei der const-Methode eine Objektkopie zurückliefern, was ich aber aus Performancegründen gerne verhindert hätte.

Viele Grüße!
Sebastian

Verfasst: 14. September 2009 12:47
von RHBaum
die frage ist sowieso, warum verwendest du zeiger ?
QString ist doch schon ne holderklasse auf nen anderweitig allocierten speicherblock. es bringt doch da doppelt verzeigern gar nix ....
da [] sowieso nen temporaeres element anlegt, brauchst auch keinen ungueltigkeitswert ... bzw nen indikator fuer.

genau so wie das int in der parameteruebergabe ned referenzieren musst. ne referenzuebergabe kopiert soweiso sizeof(void *) bytes.
int selber sollte in den meisten faellen genau so viel bytes haben.
Durch veraenderung schuetzt dich die werteuebergabe.
also ist "int" statt "const int &" als parameteruebergabe einfach nur einfacher, intuitiver und ganz kleinwenig performanter (eine dereferenzierung entfaellt)
die Map kann das natuerlich nicht vereinfachen, die weiss ja ned wie komplex der Key ist ....

Code: Alles auswählen

class c {
public:
    const QString & getPointer(int key) const { return my[key]; }
    QString & getPointer(int key){ return my[key]; }
private:
   QMap<int, QString> my;
}; 

@christian
Was meinst du genau ?
Ich hab nur die Map definition hoch schieben muessen, und schon frissts der vc2005 compiler anstandslos ....

Code: Alles auswählen

	
class c 
	{
		QMap<int, QString> my;
	public:
		const QString* getPointer(const int &key) const { return &my[key]; }
		const QString* getPointer(const int &key)          { return &my[key]; }

	private:

	}; 
Kann er bei mir zumindest compilieren und verwenden ....


ciao ...

Verfasst: 14. September 2009 12:56
von Christian81

Code: Alles auswählen

 const QString* getPointer(const int &key) const { return &my[key]; } 
 -->
  const T QMap::operator[] ( const Key & key ) const
Der MSVC-Compiler gibt hier leider keine Warnung aus. Du bekommst einen Pointer auf ein temporary object zurück. Das gibt nen Crash wenn Du drauf zugreifst :)

Verfasst: 14. September 2009 13:16
von roeseb
Hallo RHBaum,

ich habe leider seit 8 Jahren nix mehr mit C++ gemacht und bin mittlerweile durch andere Sprachen etwas "versaut" ;-)
Die Rückgabe als Referenz wäre sicher schöner, dann müsst ich aber sehr viele -> in zig includes ersetzen. :roll:
Einen grossen Vorteil von der Pointerrückgabge habe ich darin gesehehn, dass ich NULL zurückliefern kann, falls das angeforderete Element nicht in der Map vorhanden ist.
Dies ist jetzt aus meinem Beispiel aber nicht ersichtlich. Bei ner Referenz bräuchte ich dann ein explizites "NO_ENTRY" Objekt, das ich referenzieren könnte.

Die Übergabe der int-Referenz liegt daran, dass ich im richtigen Programm hier eine wesentliche größere Klasse habe, wo die Referenzübergabe schon wieder Sinn macht.

Viele Grüße!
Sebastian

Verfasst: 14. September 2009 13:49
von RHBaum
@Christian

ahhh sorry, Brett vor den augen ....
bei const ist es keine referenz sondern ne kopie

... du hasst recht

aber

@roeseb
also QMap meiden, und std::map verwenden, dass erzeugt zwar exceptions dafuer aber ne mehr intuitivere Schnittstelle ...
Du kommst nicht mal mit value() an ne konstante referenz auf den Wert, das macht QMap total untauglich fuer dein vorhaben ....

const T als rueckgabe ist einfach nur besch ....
entweder T (als kopie, hat eh keine rueckwirkung auf das erzeugende Object, also entsprichts den anforderungen von const, warum also die unnötige weitere beschraenkung ? )
oder const T & ......
Einen grossen Vorteil von der Pointerrückgabge habe ich darin gesehehn, dass ich NULL zurückliefern kann, falls das angeforderete Element nicht in der Map vorhanden ist.
Wenn du das brauchst, ok, dann sind zeiger wirklich ein gaengiger weg.
Aber dann wuerd ich mir ueberlegen das QString ned aus der schnittstelle ganz rauszunehmen ....

und nur sowas anzubieten z.b.

class c
{
public:
const QChar * getString(int key) const;
const QChar * setString(int key, const QChar * value);
private:
};

das waer ne mehr C like schnittstelle ....
alternativ QChar * durch char * ersetzen, wenn qt freiheit brauchst, und intern die STL verwendest, und dir Ascii zeichen langen.

mit zeigern auf containern arbeiten sieht einfach nur irgendwie bloed aus ^^

wenn Dir nen leerer QString als invalid wert langt, kannst wiederum ganz auf die zeiger verzichten.

Ciao ...

Verfasst: 14. September 2009 19:13
von roeseb
Hallo RHBaum,

danke für Deinen Vorschlag bezüglich QChar, aber in der richtigen Implementierung ist der Datenteil der Map kein QString sondern eine von mir geschaffene Klasse.

Ich hab mir jetzt wie folgt über iteratoren beholfen:

Code: Alles auswählen

class c {
public:
    const QString* getPointer(const int &key) const;
    const QString* getPointer(const int &key)       { return &my[key]; }

private:
   QMap<int, QString> my;
};

const QString* c::getPointer(const int &key) const {
    QMap<int, QString>::const_iterator entry;

    entry = my.find(key);
    if (entry == my.end())
        return NULL;

    return &entry.value();
}

Viele Grüße!
Sebastian