Rückgabe von Ergebnissen - unnötiges Kopieren vermeiden
-
Hallo!
Ich habe mal folgenden Operator für eine einfache Vektorklasse geschrieben:
Vector operator + (const Vector& l, const Vector& r) { Vector temp(r.size()); for(int i=0;i<r.size();i++) temp[i] = l[i] + r[i]; return temp; }
Ich erstelle ein temporäres Objekt, was wohl unvermeidlich ist. Daß temp
aber für die Rückgabe nochmals mit allen Elementen kopiert wird, erscheint
mir überflüssig.
Meine Idee ist nun, temp und den Rückgabewert von einem ResultVector-Typ
zu machen, der einfach den Zeiger auf die Daten von temp nimmt und ihn
rausreicht, ohne die Daten selbst nochmal zu kopieren.
Der Destruktor von temp dürfte also den Daten-Puffer nicht freigeben.
Daher darf ResultVector nur für diesen einen Zweck benutzt werden.
Sobbald ResultVector in Vector umgewandelt wird, ist die Magie beendet.
Damit würde wieder ein echter Destruktor mit delete die Kontrolle übernehmen.Könnte das funktionieren?
Bringt das überhaupt merklich was?
Oder gibts sowas sogar schon?Danke!
-
Ich fürchte, um eine Kopie wirst du nicht herumkommen - schließlich ist die temp-Variable lokal in deinem Operator und wird nach dem return vernichtet. Du könntest höchstens dafür sorgen, daß diese Kopie möglichst "billig" ist. (ein Ansatz dazu wäre Referenzzählung für dein unterliegendes Daten-Array - dann mußt du bei der Rückgabe nur den Pointer darauf kopieren)
-
Könnte es sein, das ein guter Compiler das eh optimiert (RVO) ?
Zu dem Thema gibt es ein schönes Kapitel in "effektiv C++ Programmieren, Meyers, Kapitel 23"
-
Hallo!
Genau diese "billige Kopie" hatte ich ja angedacht. Der Destruktor von
ResultVector gibt den Array-Speicher nicht frei. Und der Copy-Konstruktor,
der das Ergebnis rauskopiert, übernimmt den Zeiger auf diesen Speicher.
Wenn das Ergebnis einem richtigen Vektor zugewiesen wird, so
übernimmt er den Speicher und ist dann für die Freigabe verantwortlich.
Vielleicht ist das mit SmartPointern auch besser zu lösen.Wenn die "Return Value Optimization" wirklich greift, dann wäre meine Idee
wohl eine Luftnummer.Ich bin mir auch nicht sicher, wie längere verkettete Formeln ausgewertet werden.
-
Ganz so einfach, wie du dir das gedacht hast, funktioniert das vermutlich nicht:
Vector v1,v2,v3; v1+v2; // ist zwar sinnfrei, aber technisch möglich /* der zurückgegebene ResultVector gibt den Speicher nicht frei, wenn er zerstört wird (etwa auf Höhe des ;) -> du hast ein Speicherleck */ ResultVector rv = v1+v1; v2 = rv; v3 = rv; /* beide Vektoren verwenden den selben Speicher, ohne voneinander zu wissen -> bei Programmende bekommst du einen Zugriffsfehler, weil der Speicher doppelt freigegeben werden soll */
Da ist es imho besser, die Referenzzählung in der Klasse Vector einzubauen - vergrößere den vom Vector reservierten Speicherbereich um einen int und schreib dir dort rein, wieviele Vectoren diese Daten nutzen wollen - bei n==1 hast du exklusiven Zugriff (d.h. du bist auch für's Löschen zuständig), bei n>1 teilst du dir die Daten mit anderen Vectoren (Wichtig: Achte darauf, daß du ALLE Schreiboperationen dahingehend absicherst).
-
Danke für den Hinweis. Mittlerweile bin ich von der Idee abgekommen.
Selbst mit Referenzzählung glaube ich nicht, daß ich bessere Ergebnisse
kriege als bestehende Bibliotheken.Ich habe verschiedene Optimierungsmethoden gefunden...
In Stroustrups "Die C++ Programmiersprache" steht was über Vektorarithmetik,
mit dem Tip, man solle die Operation in Add unt Mult-Objekte ("Compositors")
zergliedern und die Berechnung in den Zuweisungsoperator verlegen -> keine Temporären Variablen.Noch abgefahrener ist die Implementierung mit Expression Templates (Blitz++).
Damit erreicht man die Geschwindigkeit von Fortran, ohne sich als Anwender die
Finger zu brechen (mit ganz normalen Operatoren).Für Interessenten:
http://wwwcascina.virgo.infn.it/DataAnalysis/Noise/doc/Talks/NAP_29Sept04/datacontainers240904.pdf
http://www.oonumerics.org/blitz/
http://osl.iu.edu/~tveldhui/
http://www.flipcode.com/articles/article_fastervectormath.shtml
http://osl.iu.edu/research/mtl/ (ohne Expression Templates, ohne Operatoren)Da kann ich nicht mithalten. Ich versuchs mal zu verstehen und probiere Blitz++ mal aus.
Auf jeden Fall interessant...