Antwort Q # 1
Wenn die regulären Zeiger schneller sind, und ich habe bereits freigegebenen Zeiger Welche Möglichkeiten habe ich haben, um ein Verfahren, das die freigegebenen Zeiger anrufen?
operator->
innerhalb boost::shared_ptr
has assertion:
typename boost::detail::sp_member_access<T>::type operator->() const
{
BOOST_ASSERT(px != 0);
return px;
}
So, zunächst sicher sein, dass Sie NDEBUG
definiert haben (in der Regel in Version baut es automatisch geschieht):
#define NDEBUG
Ich habe Assembler Vergleich zwischen Dereferenzierung vongemachtund Rohzeiger:
template<int tag,typename T>
NOINLINE void test(const T &p)
{
volatile auto anti_opti=0;
ASM_MARKER<tag+0>();
anti_opti = p->data;
anti_opti = p->data;
ASM_MARKER<tag+1>();
(void)anti_opti;
}
test<1000>(new Foo);
ASM
Code von test
wenn T
ist Foo*
ist (keine Angst, ich diff
unten haben):
_Z4testILi1000EP3FooEvRKT0_:
.LFB4088:
.cfi_startproc
pushq %rbx
.cfi_def_cfa_offset 16
.cfi_offset 3, -16
movq %rdi, %rbx
subq $16, %rsp
.cfi_def_cfa_offset 32
movl $0, 12(%rsp)
call _Z10ASM_MARKERILi1000EEvv
movq (%rbx), %rax
movl (%rax), %eax
movl %eax, 12(%rsp)
movl %eax, 12(%rsp)
call _Z10ASM_MARKERILi1001EEvv
movl 12(%rsp), %eax
addq $16, %rsp
.cfi_def_cfa_offset 16
popq %rbx
.cfi_def_cfa_offset 8
ret
.cfi_endproc
test<2000>(boost::make_shared<Foo>());
ASM
Code von test
wenn T
ist boost::shared_ptr<Foo>
:
_Z4testILi2000EN5boost10shared_ptrI3FooEEEvRKT0_:
.LFB4090:
.cfi_startproc
pushq %rbx
.cfi_def_cfa_offset 16
.cfi_offset 3, -16
movq %rdi, %rbx
subq $16, %rsp
.cfi_def_cfa_offset 32
movl $0, 12(%rsp)
call _Z10ASM_MARKERILi2000EEvv
movq (%rbx), %rax
movl (%rax), %eax
movl %eax, 12(%rsp)
movl %eax, 12(%rsp)
call _Z10ASM_MARKERILi2001EEvv
movl 12(%rsp), %eax
addq $16, %rsp
.cfi_def_cfa_offset 16
popq %rbx
.cfi_def_cfa_offset 8
ret
.cfi_endproc
Hier Ausgabe von diff -U 0 foo_p.asm shared_ptr_foo_p.asm
Befehl:
--- foo_p.asm Fri Apr 12 10:38:05 2013
+++ shared_ptr_foo_p.asm Fri Apr 12 10:37:52 2013
@@ -1,2 +1,2 @@
-_Z4testILi1000EP3FooEvRKT0_:
-.LFB4088:
+_Z4testILi2000EN5boost10shared_ptrI3FooEEEvRKT0_:
+.LFB4090:
@@ -11 +11 @@
-call _Z10ASM_MARKERILi1000EEvv
+call _Z10ASM_MARKERILi2000EEvv
@@ -16 +16 @@
-call _Z10ASM_MARKERILi1001EEvv
+call _Z10ASM_MARKERILi2001EEvv
Wie Sie sehen können, Unterschied nur in Funktionssignatur ist, und tag
nicht -Typ Vorlage Argument Wert, Rest des Codes ist IDENTICAL
.
Im Allgemeinen - shared_ptr
ist sehr teuer - es ist die Referenzzählung zwischen Threads synchronisiert (in der Regel über atomare Operationen). Wenn Sie stattdessen boost::intrusive_ptr
verwenden würden, können Sie Ihre eigene increment
/decrement
ohne Thread-Synchronisierung implementieren, was die Referenzzählung beschleunigen würde.
Wenn Sie es sich leisten können, unique_ptr
zu verwenden oder Semantik zu verschieben (über Boost.Move oder C++ 11) - dann wird es keine Referenzzählung geben - es wäre noch schneller.
LIVE DEMO WITH ASM OUTPUT
#define NDEBUG
#include <boost/make_shared.hpp>
#include <boost/shared_ptr.hpp>
#define NOINLINE __attribute__ ((noinline))
template<int>
NOINLINE void ASM_MARKER()
{
volatile auto anti_opti = 11;
(void)anti_opti;
}
struct Foo
{
int data;
};
template<int tag,typename T>
NOINLINE void test(const T &p)
{
volatile auto anti_opti=0;
ASM_MARKER<tag+0>();
anti_opti = p->data;
anti_opti = p->data;
ASM_MARKER<tag+1>();
(void)anti_opti;
}
int main()
{
{
auto p = new Foo;
test<1000>(p);
delete p;
}
{
test<2000>(boost::make_shared<Foo>());
}
}
Antwort Q # 2
Ich habe eine Instanz Methode (n), die schnell aufgerufen wird, die ein std :: vector auf dem Stapel jedes Mal erstellt.
Im Allgemeinen ist es ratsam, die Kapazität von vector
wiederzuverwenden, um teure Neuzuweisungen zu vermeiden.Zum Beispiel ist es besser, zu ersetzen:
{
for(/*...*/)
{
std::vector<value> temp;
// do work on temp
}
}
mit:
{
std::vector<value> temp;
for(/*...*/)
{
// do work on temp
temp.clear();
}
}
Aber sieht aus wie durch std::map<std::string,std::vector<std::string>*>
geben Sie versuchen, irgendeine Art von memoization perfom.
Wie bereits vorgeschlagen, statt std::map
die hat O (ln (N)) Lookup/fügen Sie boost::unordered_map
/std::unordered_map
zu verwenden, können versuchen, die O (1) Durchschnitt und O (N) hat worst Case-Komplexität für Lookup/Einfügung, und bessere Lokalität/Compactess (Cache-freundlich).
Auch COSIDER versuchen Boost.Flyweight:
Flyweights sind kleine Behandlungsklassen ständigen Zugriff auf gemeinsam genutzten Daten gewähren, damit für die Verwaltung großer Mengen von Einheiten innerhalb einer angemessenen Speichergrenzen zu ermöglichen. Boost.Flyweight macht es einfach, diese allgemeine Programmiersprache zu verwenden, indem die Klassenvorlage flyweight, die als ein Drop-in-Ersatz für const T dient.
Donald Knuth: "Wir sollten kleine Wirkungsgrade vergessen, sagen etwa 97% der Zeit: vorzeitige Optimierung ist die Wurzel allen Übels" => Profil zuerst, identifizieren Sie die Hotspots, optimieren Sie diese **. –