Expression-Vorlagen werden häufig als Optimierungstechnik verwendet, um die Erstellung temporärer Objekte zu vermeiden. Sie verzögern das Konstruieren des vollständigen Objekts, bis die Vorlage in einer Zuweisung oder Initialisierung verwendet wird. Dies findet Verwendung in String-Buildern, linearen Algebra-Paketen usw.
Um teure Kopien zu vermeiden, kann die Ausdruckvorlagenklasse die größeren Argumente als Referenz erfassen. Ich werde Qt QStringBuilder
als ein Beispiel verwenden.
Es funktioniert, wenn die Referenzen die Ausdrucksvorlage überlisten:
%Vor%Die Konvertierung und Auflösung der Expression-Vorlage geschieht bei der Zuweisung. Die String-Provisorien überleben die Zuweisung.
Leider stoßen wir auf Probleme, sobald der Ausdruckschablonentyp anstelle des Zieltyps abgeleitet wird:
%Vor%Und auch:
%Vor% Eine Lösung besteht darin, dass der Builder Kopien von Objekten speichert. Da QString
s hier implizit geteilt werden, ist ihr Kopieren billig, obwohl es immer noch teurer ist, als eine Referenz zu halten. Angenommen, die Argumente lauten std::string
: Sie sollten sie auf jeden Fall nicht kopieren wollen, wenn dies nicht notwendig ist.
Gibt es eine Technik, die verwendet werden könnte, um zu erkennen, dass ein vollständiger Template-Ausdruck nicht sofort aufgelöst wird und die Daten kopiert werden müssen, wird bisher nur ein Verweis auf?
gehalten Hinweis: Ich frage nicht nach einer bestimmten vorhandenen Implementierung von Ausdrucksvorlagen. Ich verwende nur QStringBuilder
als motivierendes Beispiel. Dies ist keine Qt-Frage oder eine Eigenfrage, etc. Der Titel ist die Frage, ziemlich genau.
Sie können möglicherweise nicht zuverlässig erkennen, wenn eine Referenz auf ein Objekt ungültig wird, es sei denn, das Objekt gibt einen Hinweis darauf, dass es ungültig gemacht wird. Sie können auch nicht im Voraus erkennen, ob eine bestimmte Funktion für Ihre Ausdrucksobjekte aufgerufen wird. Sie können nur erkennen, dass sie aufgerufen wurde, als sie tatsächlich aufgerufen wurde.
Wenn Ihr Objekt eine Möglichkeit bietet, die Zerstörung zu erkennen, zum Beispiel wenn es ein Ereignissystem gibt, das Ihnen davon erzählt, dann sollten Sie in der Lage sein, Ihre Ausdrucksobjekte zu ändern. Halten Sie statt einer Referenz auf die ursprünglichen Datenobjekte eine markierte Union. Speichern Sie zunächst einen Zeiger auf die ursprünglichen Datenobjekte. Wenn diese Datenobjekte zerstört werden sollen, kopieren Sie die Daten und aktualisieren Sie das Tag.
Beachten Sie jedoch, dass dies das Problem nicht auf andere Weise verhindert. Ein Objekt wurde zum Beispiel aus diesem Objekt entfernt, und obwohl das Objekt noch immer nicht zerstört wurde, sind die Daten, die es enthält, im sinnvollen Sinn des Wortes nicht mehr sinnvoll.
>Letztendlich denke ich, dass Sie versuchen, technische Mittel zu verwenden, um ein nicht-technisches Problem zu lösen: Sie haben (vernünftigerweise, IMO) entschieden, dass Sie Ihre Daten nicht kopieren wollen, wenn die Ausdrücke konstruiert werden, nicht einmal wenn die Datenobjekte COW verwenden. Sie müssen Ihre Benutzer entweder über die Konsequenzen dieser Entscheidung aufklären oder Ihre Entscheidung überarbeiten.
Gibt es eine Technik, die verwendet werden könnte, um zu erkennen, dass ein vollständiger Template-Ausdruck nicht sofort aufgelöst wird und die Daten kopiert werden müssen, wird bisher nur ein Verweis auf?
gehalten
Das passiert hauptsächlich, wenn Sie Builder
kopieren, damit Sie das in Ihrem Kopierkonstruktor verwalten können:
, aber es schlägt immer noch fehl, wenn Sie die Lebensdauer von temporär mit der const-Referenz
verlängern %Vor%Tags und Links c++ templates expression-templates