Wie viel kostet die Verwendung von Smartpointern, insbesondere boost :: shared_ptr, im Vergleich zu bloßen Zeigern in Bezug auf Zeit und Speicher? Sind bare Pointer besser für leistungsintensive Teile von Gaming/Embedded Systemen geeignet? Würden Sie bare Pointer oder Smartpointer für leistungsintensive Komponenten empfehlen?C++ Smart Pointer Leistung
Antwort
Dereferenzierung intelligente Zeiger typischerweise trivial ist, sicherlich für Auftrieb im Release-Modus. Alle Boost-Prüfungen sind zur Kompilierungszeit. (Intelligente Zeiger könnten theoretisch cleveres Zeug über Threads hinweg machen). Dies führt immer noch zu vielen anderen Operationen. Nicola erwähnte Konstruktion, Kopie und Zerstörung. Dies ist jedoch nicht das komplette Set. Andere wichtige Operationen sind Swapping, Zuweisung und Zurücksetzen auf NULL. Grundsätzlich jede Operation, die Intelligenz erfordert.
Beachten Sie, dass einige dieser Operationen von einigen Smartpointern ausgeschlossen sind. Z.B. boost::scoped_ptr
kann nicht einmal kopiert, geschweige denn zugewiesen werden. Da weniger Operationen erforderlich sind, kann die Implementierung für diese weniger Methoden optimiert werden.
In der Tat, mit TR1 kommt, ist es ziemlich wahrscheinlich, dass Compiler besser mit intelligenten Zeigern als rohen Zeigern tun können. Z.B. Es ist möglich, dass ein Compiler beweisen kann, dass ein intelligenter nicht kopierbarer Zeiger in einigen Situationen kein Alias ist, nur weil er nicht kopierbar ist. Denken Sie darüber nach: Aliasing tritt auf, wenn zwei Zeiger erstellt werden, die auf dasselbe Objekt zeigen. Wenn der erste Zeiger nicht kopiert werden kann, wie würde dann ein zweiter Zeiger auf dasselbe Objekt zeigen? (Es gibt auch andere Möglichkeiten - Operator * muss einen lvalue zurückliefern)
Boost bieten verschiedene Smartpointer. Im Allgemeinen sollten sowohl die Speicherbelegung, die je nach Art des Smartpointers variiert, als auch die Leistung kein Problem darstellen. Für einen Leistungsvergleich können Sie diese http://www.boost.org/doc/libs/1_37_0/libs/smart_ptr/smarttests.htm überprüfen.
Wie Sie sehen können, werden nur Konstruktion, Kopie und Zerstörung für den Leistungsvergleich berücksichtigt, was bedeutet, dass die Dereferenzierung eines intelligenten Zeigers angeblich die gleichen Kosten wie die eines rohen Zeigers hat.
Der folgende Ausschnitt zeigt, dass es keine Performance-Verlust ist durch eine shared_ptr<>
anstelle eines Rohzeiger mit:
#include <iostream>
#include <tr1/memory>
int main()
{
#ifdef USE_SHARED_PTR
std::tr1::shared_ptr<volatile int> i(new int(1));
#else
volatile int * i = new int(1);
#endif
long long int h = 0;
for(long long int j=0;j < 10000000000LL; j++)
{
h += *i;
}
std::cout << h << std::endl;
return 0;
}
Smart-Pointer mit Referenzzählung (der gebräuchlichste Typ) kosten nur mehr, wenn Sie sie kopieren, erstellen und löschen. Diese zusätzlichen Kosten können erheblich sein, wenn Sie viel kopieren, da die meisten davon Thread-sicher sind.
Wenn Sie nur einen "Auto-Löschen" -Zeiger wollen, gibt es die viel verleugnete auto_ptr, oder die neue und glänzende (aber nicht viel unterstützt noch) unique_ptr von C++ 0x.
Als ich das letzte Mal mit VC6 getestet habe, war der Compiler nicht in der Lage, den Code mit einem intelligenten Zeiger zu optimieren, so wie es mit einem rohen Zeiger möglich wäre. Die Dinge könnten sich seitdem geändert haben.
Als ich mit VC6 zum letzten Mal eine ältere Version von Boost (1,34, glaube ich) getestet habe, hat der Compiler das atomare Inkrement des refcount für einen weak_ptr optimiert. Das führte dazu, dass die Dinge wesentlich schneller liefen, obwohl es in den Thread-Bibliotheken einige Abstürze gab. – Michel
VC6 Ich merke, dass immer noch stark von großen Projekten verwendet wird, die nicht einfach wechseln können, aber lass uns fair sein, es war kein ausgereifter Compiler bis VC2003, der 2. Veröffentlichung innerhalb des VS.NET-Produktlebenszyklus. – ApplePieIsGood
Die einzige Möglichkeit, mit Leistungsproblemen umzugehen, besteht darin, den Code zu profilieren. Der größte Teil von Leistungsproblemen wird sowieso vorgestellt; Nur das Profiling zeigt Ihnen, wo Ihre Engpässe liegen.
Wenn es sich herausstellt, dass die Verwendung von Smartpointern einen Engpass erzeugt, wo rohe Pointer keine sind, verwenden Sie rohe Pointer! Bis dahin würde ich mir nicht zu viele Sorgen machen; Die meisten Operationen mit intelligenten Zeigern sind ziemlich schnell. Sie werden Strings wahrscheinlich zu oft (oder so ähnlich) vergleichen, damit sie wichtig sind.
Es gibt ein oft übersehenes Zwischenhaus zwischen einem "manuell" verwalteten std::vector<T*>
(dh rohe Zeiger) und einem std::vector<boost::shared_ptr<T> >
, in Form der boost::ptr_container
Klassen.
Diese kombinieren die Leistung eines Rohzeiger Behälter mit dem Komfort eines Behälters von Smart Pointer (dh sie bieten die Funktionalität Menschen STL-Container von std::auto_ptr
möchten bieten, if that worked).
Leider funktioniert Ihre Idee für optimierte Smart Pointer nicht, zumindest in C++. Möglicherweise haben Sie den Zeiger anderswo gespeichert, bevor Sie ihn in den Smart Pointer setzen. Außerdem ist es einfach (aber nicht ratsam), den rohen C-Zeiger aus einem intelligenten Zeiger zurück zu bekommen, indem man & * smart_ptr; –
stimme ich mit Chris Jefferson überein. niemand hält Sie davon ab, es woanders zu speichern, bevor Sie es in den Smart Pointer setzen –
Ich habe hier eine kleine Antwort über Aliasing geschrieben: http://StackOverflow.com/Questions/270408/is-it-Better-in-c-to- Pass-by-value-or-pass-by-constant-Referenz # 271344 –