Seite 1 von 1

QHash löschen / Speicher freigeben

Verfasst: 22. Januar 2011 11:21
von marvel
Hallo,
ich habe einen QHash der einen QString als key und einen Pointer einer Klasse als value aufnimmt. Während der Laufzeit erzeuge ich mit new Objekte und speichere dann die Pointer im Hash. Wenn ich mit dem Hash fertig bin bzw mit den Daten gearbeitet habe möchte ich diese löschen bzw den Speicher wieder freigeben. Das mache ich folgendermaßen :

Code: Alles auswählen

if(!relationContainer.isEmpty())
	{
		QHashIterator<QString, OSM_Relation*> i(relationContainer);
		while (i.hasNext())
		{
			i.next();
			delete i.value();
		
		}
		relationContainer.clear();
	}

	if(!wayContainer.isEmpty())
	{
		QHashIterator<QString, OSM_Way*> x(wayContainer);
		while (x.hasNext())
		{
			x.next();
			delete x.value();
		}
		wayContainer.clear();
	}

	if(!nodeContainer.isEmpty())
	{
		QHashIterator<QString, OSM_Node*> k(nodeContainer);
		while (k.hasNext())
		{
			k.next();
			delete k.value();
		}
		nodeContainer.clear();
	}
Wenn größere Datenmengen verarbeitet werden, also der Hash mehrere Tausend Objekte speichert dauert das löschen des Hashs sehr sehr lange. Nun stelle ich mir die Frage ob es nicht vllt eine schnellere, performantere Methode gibt den Hash und dessen Inhalt zu löschen. Über eure Hilfe würde ich mich freuen.

MfG

marvel

Verfasst: 22. Januar 2011 11:47
von Christian81
Nein, gibt es nicht. qDeleteAll() geht auch nur über alle Elemente drüber. Die Abfrage auf isEmpty() ist blödsinnig und QHashIterator ist etwas langsamer als der stl-Iterator von QHash (siehe Doku), delete k.next().value() sollte auch gehen. Aber ich denke eher die Zeit geht beim delete drauf. Mit valgrind/callgrind kann man da genauer schauen.

Verfasst: 22. Januar 2011 12:41
von padreigh
Dir geht es ja darum ALLES zu löschen - Iteratoren zu nutzen ist ja Vorbildlich.

Im Sinne des Verständnisses, wie wäre es hiermit:

Code: Alles auswählen

foreach(OSM_Relation* rel, relationContainer.values())
{
    delete rel;
}
relationContainer.clear();

Ich weiss nicht wie Performant das im Gegenzug ist - müsstest du mal testen. Sollte ein tick langsamer sein als die STL iteratoren, da erst eine Liste vom values aufgestellt wird (zumindest wenn das intern über ebenso über STL::iteratoren läuft, wenn die da einen Trick benutzen kanns schneller sein).


Wenn es zeitkritisch ist und du nen Mehrprozessor hast, wie wäre es hiermit? (pseudocode)

Code: Alles auswählen

inline void deleteIt(OSM_Relation* rel)
{
    delete rel;
}


QtConcurrent::map(relationContainer.values(), deleteIt);

Verfasst: 23. Januar 2011 04:58
von marvel
Die Abfrage auf isEmpty() ist blödsinnig
da muss ich dir recht geben, diese abfrage ist überflüssig...

danke für die schnellen antworten, ich habe das ganze jetzt mit der foreach variante gelöst.

Verfasst: 23. Januar 2011 09:38
von Christian81
Foreach ist aber definitiv langsamer als die normalen Iteratoren...
Wie gesagt - valgrind ist hier wohl das richtige Mittel der Wahl.

Verfasst: 23. Januar 2011 12:00
von padreigh
#include<qglobal.h> hat geschrieben:

Code: Alles auswählen

#if defined(Q_CC_GNU) && !defined(Q_CC_INTEL) && !defined(Q_CC_RVCT)
/* make use of typeof-extension */
template <typename T>
class QForeachContainer {
public:
    inline QForeachContainer(const T& t) : c(t), brk(0), i(c.begin()), e(c.end()) { }
    const T c;
    int brk;
    typename T::const_iterator i, e;
};

#define Q_FOREACH(variable, container)                                               \
for (QForeachContainer<__typeof__(container)> _container_(container); \        /* geinlinter Konstructor, implict data sharing -> Kopiert datenpointer */
     !_container_.brk && _container_.i != _container_.e;                           \       /* .brk==0 und .begin(bzw laufindex) != .end()  */
     __extension__  ({ ++_container_.brk; ++_container_.i; }))               \
    for (variable = *_container_.i;; __extension__ ({--_container_.brk; break;}))

#else
/* egal */

Ohne Compileroptimierung ist das wohl etwas langsamer als gleich die STLiteratoren zu nehmen da zumindest ein Pointer mehr kopiert wird ... ich hab noch nie valgrind benutzt, mag mir jemand sagen wie man das (ca) damit testen könnte? Weiss jemand was das _container_.brk; machen soll? Ich würde mal "vermuten" das es bei "break" nochmals incrementiert (oder nicht dekrementiert) wird und dann für den schnellen ausstieg aus schleife 1 sorgt? Ich nehme mal an das __extension__ durch den Rumpf des foreach's ersetzt wird?