Garantierte Erkennung von temporär benannten Punkten

8

Angenommen, Sie schreiben eine Matrixklasse mit einigen Operationen:

%Vor%

Es ist sinnvoll, die Auswertung einiger Matrixausdrücke zu verschieben: m0 * m1 * m2 * m3 * m4 (eine Folge von vier operator* -Aufrufen) kann von der Verwendung von dynamischer Programmier-Matrix-Ketten-Multiplikationsalgorithmus ; die sehr häufige m0 * m1 t hat eine sehr effiziente dgemm Implementierung und so weiter.

Es zahlt sich folglich aus, die eigentliche Berechnung aufzuschieben, bis sie benötigt wird. Dies ändert das obige zu:

%Vor%

Jede Matrix enthält einen Zeiger auf ein Basisklassenobjekt, das von einer realen Matrix bis zu einem komplizierten Ausdrucksbaum reichen kann. Jede Operation versucht, eine Matrix zu bilden, die die faulste Änderung der internen Implementierung verwendet. Einige Operationen haben keine andere Wahl, als Dinge tatsächlich zu bewerten, die Ausdrucksstruktur zu komprimieren und die interne Implementierung auf eine tatsächliche Matrix zu setzen.

Das Problem war, dass dies in der Praxis in sehr häufigen Fällen zu einem enormen Speicheraufwand führte. Nehmen wir an, Sie lesen aus einer Datei eine lang-und-schmale Matrix x = x p X q , p & gt; & gt; q , speichern Sie x t x in einer Variablen und verwerfen Sie x . Bei einer faulen Bewertung ist der Speicher pq & gt; & gt; qq . Laden Sie diese in eine Schleife, und das ist ein ernstes Problem. (Natürlich kann die Komprimierung nach jedem Laden durch den Clientcode, der operator() aufruft, erzwungen werden, aber dies ohne algorithmische Begründung zu erfordern, ist hässlich und fehleranfällig.)

Anfangs dachte ich, dass der move ctor ein guter Punkt für die automatische Komprimierung ist - genau an dem Punkt, an dem ein temporäres Objekt zu einem benannten Objekt wird und seine Objekte einen erhöhten Speicherverbrauch verursachen, also

%Vor%

scheint alles zu lösen, z.B.

%Vor%

aber kann man darauf zählen? Zum Beispiel, bedenken

%Vor%

ist der Compiler verboten, in (*) zu tun, ähnlich wie bei der NRVO , nämlich nur um es an Ort und Stelle zu bauen? Selbst wenn nicht, könnte ein Compiler Dinge in anderen Fällen optimieren?

    
Ami Tavory 02.06.2015, 11:38
quelle

1 Antwort

2

Da die "interne Zeiger" -Methode nicht die gesamte Flexibilität bieten kann, die für die verzögerte Auswertung benötigt wird, besteht die typische Lösung, die von numerischen C ++ - Bibliotheken verwendet wird, darin, spezialisierte Klassen zu definieren, die faule Auswertemechanismen implementieren. Die alte SO-Frage Lazy Evaluation in C ++ und ihre besten Antworten zeigen die Grundlagen eines solchen Designs und einige Beispielcode.

Obwohl ich kein Experte bin, denke ich, gute Beispiele für diese Architektur sind die numerischen Bibliotheken Eigen ( hier einige Details über seine Implementierung ) und Blitz ++, das sich stark auf Vorlagen stützt (ich habe im Internet keine aktualisierte Dokumentation gefunden, die seine Interna darstellt, aber Dieser Artikel beschreibt einen Teil seiner Engine und bietet einen weiteren Überblick über die" Expression Template "-Technik.

    
Alberto M 02.06.2015, 20:16
quelle