Die effiziente Verwendung von %code% ohne redundante Kopien ist nicht offensichtlich
Zusätzlich dazu, dass der akkumulierende Wert neu zugewiesen und in und aus dem Lambda übergeben wird, kann er intern durch die Implementierung kopiert werden.
Beachten Sie außerdem, dass %code% selbst den Anfangswert by-value verwendet , einen copy-ctor aufrufen und somit% code% s ignorieren, das auf der Quelle der Kopie ausgeführt wurde (wie in einigen der anderen Antworten vorgeschlagen).
Der effizienteste Weg, die Strings zu verketten, ist folgender:
%Vor% Das Ergebnis wird in %code% angezeigt.
Diese Implementierung enthält keine redundanten Kopien, Verschiebungen oder Neuzuordnungen.
Versuchen Sie Folgendes
%Vor%Vor diesem Aufruf ist es vielleicht sinnvoll,
anzurufen %Vor%Dies ist ein bisschen schwierig, da zwei Operationen sind, der Zusatz und die Zuordnung. Um die Kopien zu vermeiden, Sie müssen die Zeichenfolge im Zusatz und ändern Stellen Sie sicher, dass die Zuweisung ein No-Op ist. Es ist der zweite Teil Das ist schwierig.
Was ich gelegentlich getan habe, ist einen benutzerdefinierten "Akkumulator" zu erstellen, in Anlehnung an:
%Vor%Beim Aufruf von %code% und von Rückgabewert, aber während der tatsächlichen Akkumulation nichts. Gerade Aufrufen:
%Vor%(Wenn Sie sich wirklich Gedanken über die Leistung machen, können Sie hinzufügen ein Kapazitätsargument für den Konstruktor von %code% , so dass es möglich ist Führen Sie %code% für die Member-Zeichenfolge aus. Wenn ich das täte, würde ich schreiben Sie wahrscheinlich auch den Kopierkonstruktor, um das sicherzustellen Die Zeichenfolge im kopierten Objekt hatte die erforderliche Kapazität.)
Ich würde dies in zwei Operationen aufteilen, zuerst %code% , um die Gesamtlänge der zu erstellenden Zeichenfolge zu erhalten, dann eine %code% mit einem Lambda, das die lokale Zeichenfolge aktualisiert:
%Vor%Die gebräuchlichste Alternative ist die Verwendung von Ausdrucksvorlagen, die jedoch nicht in eine Antwort passen. Grundsätzlich erstellen Sie eine Datenstruktur, die die Operationen abbildet, aber nicht ausführt. Wenn der Ausdruck schließlich ausgewertet wird, kann er die Informationen, die er benötigt, im Voraus sammeln und verwenden, um den Platz zu reservieren und die Kopien zu erstellen. Der Code, der die Ausdrucksvorlage verwendet, ist schöner, aber komplizierter.
Angenommen, ich habe einen Vektor von Strings und möchte sie über std :: accumulate verketten.
Wenn ich den folgenden Code verwende:
%Vor%Ich kann ziemlich sicher sein, dass es eine temporäre Objektkonstruktion geben wird.
In dieser Antwort wird gesagt, dass der Effekt von std :: accumulate folgendermaßen angegeben wird:
Berechnet das Ergebnis durch Initialisierung des Akkumulators acc mit Initialwert init und ändert es dann mit acc = acc + * i oder acc = binary_op (acc, * i) für jeden Iterator i im Bereich [first, last] in bestellen.
Also frage ich mich, was ist der richtige Weg, dies zu tun, um die unnötige temporäre Objektkonstruktion zu vermeiden.
Eine Idee war, das Lambda so zu ändern:
%Vor% In diesem Fall dachte ich, dass ich eine effiziente Verkettung der Strings erzwinge und dem Compiler helfe (ich weiß, dass ich
und somit
%Vor%Eine andere Idee war es,
zu verwenden %Vor%Aber das würde wahrscheinlich zu etwas wie:
führen %Vor%Was mir sehr verdächtig erscheint.
Was ist der richtige Weg dies zu schreiben, um das Risiko der unnötigen Erstellung von temporären Objekten zu minimieren? Ich interessiere mich nicht nur für std :: string, ich wäre glücklich, eine Lösung zu haben, die wahrscheinlich für jedes Objekt funktionieren würde, das Kopier- und Verschiebungskonstruktoren / Zuordnungen implementiert hat.