C ++: Warum Pass-by-Wert im Allgemeinen effizienter ist als Pass-by-Referenz für eingebaute (dh c-ähnliche) Typen

StackOverflow https://stackoverflow.com/questions/5346853

Frage

Genauso was im Titel angegeben hat

War es hilfreich?

Lösung

Ein Compiler -Anbieter würde normalerweise eine Referenz als Zeiger implementieren. Zeiger sind in der Regel in der gleichen Größe wie oder größer als viele der eingebauten Typen. Für diese eingebauten Typen würde die gleiche Datenmenge übergeben, unabhängig davon, ob Sie nach Wert oder Referenz bestanden haben. Im Die Funktion, um die tatsächlichen Daten zu erhalten, müssen Sie jedoch diesen internen Zeiger Dereference müssten. Dies kann dem generierten Code eine Anweisung hinzufügen, und Sie werden auch haben zwei Speicherorte, die möglicherweise nicht im Cache liegen. Der Unterschied wird nicht viel sein - aber er könnte in engen Schleifen gemessen werden.

Ein Compiler-Anbieter könnte sich dafür entscheiden, Const-Referenzen (und manchmal auch nicht konstete Referenzen) zu ignorieren, wenn sie auf integrierten Typen verwendet werden-abhängig von den Informationen, die dem Compiler zur Verfügung stehen, wenn er sich mit der Funktion und ihren Anrufern befasst.

Andere Tipps

Für POD -Typen wie int, char, Short und Float ist die Größe der Daten gleich groß (oder kleiner) als die Adresse, die in die tatsächlichen Daten übergeben wurde. Die Suche nach dem Wert an der referenzierten Adresse ist ein unnötiger Schritt und fügt zusätzliche Kosten hinzu.

Nehmen Sie zum Beispiel die folgenden Funktionen foo und bar

void foo(char& c) {...}
void bar(char c) {...}

Wann foo Eine Adresse wird bezeichnet, wird je nach Plattform entweder 32bit oder 64Bit übergeben. Wenn Sie verwenden c innerhalb foo Sie haben die Kosten, um den Wert der Daten zu suchen, die an der in der Adresse bestehenden Daten enthalten sind.

Beim Anruf bar Ein Wert der Größe von Char wird eingeleitet und es gibt keine Adress -Lookup -Overhead.

In der Praxis implementieren C ++ Implementierungen im Allgemeinen Pass-by-Referenz, indem sie einen Zeiger unter die Haube übergeben (vorausgesetzt, der Anruf ist nicht eingefügt).

Es gibt also keinen cleveren Mechanismus, der es zulässt, dass Pass-by-Reference schneller ist, da es nicht schneller ist, einen Zeiger zu bestehen, als einen kleinen Wert zu bestehen. Und Pass-by-Wert kann auch von einer besseren Optimierung profitieren, wenn Sie in der Funktion sind. Zum Beispiel:

int foo(const int &a, int *b) {
    int c = a;
    *b = 2;
    return c + a;
}

Für alle Compiler weiß, dass b verweist auf a, was als "Aliasing" bezeichnet wird. Hatte a wurde von Wert übergeben, diese Funktion könnte das Äquivalent von optimieren *b = 2; return 2*a;. In einer modernen CPU -Anweisungspipeline kann dies eher wie "Starten Sie ein Laden, starten Sie B -Speichern, warten Sie, warten Sie, bis A mit 2 multiplizieren, bis B speichern, zurückkehren", anstatt "Starten Sie ein Laden, starten , Warten Sie, bis A geladen werden kann, warten Sie, bis B speichert, ein Laden, warten Sie, bis A laden kann, A bis C hinzuzufügen, zurückzugeben. " In einigen Fällen, wenn nicht unbedingt ein großer Effekt in diesem.

Natürlich behindert Aliasing nur die Optimierung, wenn sie den Effekt der Funktion für eine mögliche Eingabe ändert. Aber nur weil Ihre Absicht für die Funktion darin besteht, dass das Aliasing die Ergebnisse nie beeinflussen sollte, bedeutet dies nicht unbedingt, dass der Compiler dies nicht tut: Manchmal tritt in Ihrem Programm kein Aliasing auf, aber der Compiler tut es nicht Ich weiß das nicht. Und es muss keinen zweiten Zeigerparameter geben, wenn Ihre Funktion Code aufruft, die der Optimierer "nicht sehen kann", muss davon ausgegangen werden, dass sich eine Referenz ändern könnte.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top