回答问题#1
如果常规指针更快并且我已经有了共享指针,我有哪些选项可以调用共享指针指向的方法?
operator->
内boost::shared_ptr
有断言:
typename boost::detail::sp_member_access< T >::type operator-> () const
{
BOOST_ASSERT( px != 0 );
return px;
}
因此,首先,请确保您已NDEBUG
定义(通常在发布版本中它是自动完成的):
#define NDEBUG
我在取消引用boost::shared_ptr
和原始指针之间进行了汇编程序比较:
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
test
什么时候的代码T
是Foo*
(不要害怕,我在diff
下面):
_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
test
什么时候的代码T
是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
这是diff -U 0 foo_p.asm shared_ptr_foo_p.asm
命令的输出:
--- 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
如您所见,区别仅在于函数签名和tag
非类型模板参数值,其余代码为IDENTICAL
.
一般来说 -shared_ptr
非常昂贵 - 它的引用计数在线程之间同步(通常通过原子操作)。如果您要boost::intrusive_ptr
改用,那么您可以实现自己的increment
/decrement
不使用线程同步,这将加快引用计数。
如果你负担得起使用unique_ptr
或移动语义(通过Boost.Move或 C++11)——那么就不会有任何引用计数——它会更快。
带 ASM 输出的现场演示
#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>());
}
}
回答问题#2
我有一个快速调用的实例方法,每次都会在堆栈上创建一个 std::vector 。
通常,尝试重用vector
's 容量以防止代价高昂的重新分配是个好主意。例如最好替换:
{
for(/*...*/)
{
std::vector<value> temp;
// do work on temp
}
}
和:
{
std::vector<value> temp;
for(/*...*/)
{
// do work on temp
temp.clear();
}
}
但是由于类型的原因,std::map<std::string,std::vector<std::string>*>
您似乎正在尝试执行某种记忆。
正如已经建议的那样,您可以尝试使用具有std::map
O ( 1)平均和O(N)最坏情况复杂度的查找/插入以及更好的局部性/紧凑性,而不是O(ln(N))查找/插入 (缓存友好)。boost::unordered_map
std::unordered_map
另外,考虑尝试Boost.Flyweight:
享元是小型句柄类,授予对共享公共数据的持续访问权限,因此允许在合理的内存限制内管理大量实体。Boost.Flyweight通过提供类模板flyweight可以轻松使用这种常见的编程习惯,它充当const T的替代品。