Um Funktionen die Möglichkeit zu geben, den Vektor zu ändern, kann ich nicht
%Vor%Aber ich muss tun:
%Vor%(wie die Antworten meiner anderen Frage gezeigt haben)
Ich werde dann eine Menge Aufrufe an myvec.at()
machen. Wie schnell ist es, verglichen mit dem ersten Beispiel, das eine Variable verwendet, um das Ergebnis zu speichern?
Gibt es eine andere Möglichkeit für mich? Kann ich irgendwie Zeiger verwenden?
Wenn es ernst wird, wird es Tausende von Anrufen zu myvec.at()
pro Sekunde geben. Also ist jeder kleine Performance-Esser wichtig.
Sie können eine Referenz verwenden:
%Vor% Die Funktion at
member prüft die Grenzen, um sicherzustellen, dass das Argument innerhalb der Größe von vector
liegt. Profiling ist nur eine Möglichkeit genau zu wissen, um wie viel langsamer es im Vergleich zu operator[]
ist. Wenn Sie hier eine Referenz verwenden, können Sie die Suche einmal durchführen und dann das Ergebnis an anderen Stellen verwenden. Und Sie können es zu einem Verweis-zu- const
machen, wenn Sie sich davor schützen wollen, den Wert versehentlich zu ändern.
Aus meinen eigenen Tests mit ähnlichem Code (kompiliert unter gcc und Linux) kann operator[]
merklich schneller sein als at
, nicht wegen der Überprüfung der Grenzen, sondern wegen des Overheads der Ausnahmebehandlung. Ersetzen von at
(was eine Ausnahme auf Out-of-Bounds wirft) mit meinen eigenen Grenzen, die das Überprüfen einer Assertion auslösen auf Out-of-Bounds hat eine messbare Verbesserung gebracht.
Unter Verwendung einer Referenz, wie sagte Kristo , können Sie nur Überschreiten Sie die Grenzen Überprüfung einmal Overhead.
Beim Ignorieren der Überprüfung der Grenzen und des Overheads für die Ausnahmebehandlung sollten sowohl operator[]
als auch at
so optimiert werden, dass sie dem direkten Array-Zugriff oder dem direkten Zugriff über den Zeiger entsprechen.
Wie Chris Becke sagte, gibt es keinen Ersatz für Profiling.
Wenn die Leistung ein Problem darstellt, kann Profiling nicht ersetzt werden. Die Optimierungsmöglichkeiten von Compilern ändern sich von Version zu Version und winzige, unbedeutende Änderungen am Quellcode können die resultierende Leistung dramatisch verändern.
Niemand kann diese Frage beantworten, aber Sie selbst: Erstellen Sie eine Testumgebung und werfen Sie mehrere Algorithmen darauf und sehen Sie, was Sie bekommen.
ps. Wenn die Leistung wirklich ein Problem ist, dann habe ich einen Geschwindigkeitszuwachs von Faktor 10 aus einem PNG-Decoder bekommen, indem ich die Vektoren entfernt und durch rohe Arrays ersetzt habe. Auch dies war für Visual Studio 6. Ich behaupte nicht, dass eine rohe Array-Ersetzung Ihnen eine Verbesserung von Faktor 10 bringt, aber es ist etwas, das Sie ausprobieren sollten.
Der Grund, warum der erste nicht funktioniert, ist, dass Sie keinen Zeiger oder Iterator auf die Adresse der i-ten Variablen setzen. Stattdessen setzen Sie curr gleich dem Wert der i-ten Variablen und ändern dann curr. Ich nehme an, dass doThis und doThat Referenzen sind.
Mach das:
%Vor% Der Operator [] ist möglicherweise schneller als at
, weil die Überprüfung der Grenzen nicht erforderlich ist.
Sie können curr
zu einer Referenz machen, um das zu tun, was Sie wollen.
Sie können auch ein Benchmarking durchführen, bevor Sie sich Sorgen machen. Moderne Prozessoren können problemlos Tausende von Operationen pro Sekunde verarbeiten.
Optionen, die ich in ungefähr umgekehrter Reihenfolge der Präferenz sehe:
[]
anstelle von at()
. at()
einmal auf und speichern Sie sie in einer Referenz (siehe Kristos Antwort oben). Ehrlich gesagt, was Sie tun sollten, ist, mit den vier verschiedenen Ansätzen zu spielen und einfach den zu verwenden, der den am einfachsten zu verstehenden Code erzeugt. In den meisten Fällen sind wir froh, ein paar Maschinenzyklen für Code zu opfern, der für den Menschen leichter zu warten ist.
Die Komplexität von at()
ist konstant, d. h. in der Praxis bedeutet dies, dass sie so ausgelegt sein muss, dass sie keine relevante Leistungseinbuße aufweist.
Sie können []
verwenden, was ebenfalls eine konstante Komplexität ist, aber keine Grenzen überprüft. Dies wäre äquivalent zur Zeigerarithmetik und somit möglicherweise ein Bit schneller als das erste.
In jedem Fall ist der Vektor speziell für den konstanten Leistungszugriff auf jedes seiner Elemente ausgelegt. Das sollte also die geringste Sorge sein.
Vektoren sind am besten für die Zugriffsgeschwindigkeit geeignet. Der Zugriff auf ein zufälliges Element in einem Vektor hat die Komplexität O (1) verglichen mit O (n) für allgemeine verknüpfte Listen und O (log n) für Verbindungsbäume.
Diese Frage ist jedoch falsch gestellt, da die Antwort auf Ihre andere Frage Sie in die Irre geführt hat, indem Sie nicht erklärt haben, wie Sie Ihr ursprüngliches Problem mithilfe einer Referenz beheben können.
Wenn Sie einen Vektor laden, dann verarbeiten Sie ihn, ohne weitere Elemente hinzuzufügen oder zu löschen. Ziehen Sie dann einen Zeiger auf das zugrunde liegende Array und verwenden Sie Array-Operationen, um den Vektor-Overhead zu vermeiden. .
Wenn Sie Elemente als Teil Ihrer Verarbeitung hinzufügen oder löschen, ist dies nicht sicher, da das zugrunde liegende Array an irgendeiner Stelle durch den Vektor selbst verschoben werden kann.