C++ 通过共享ptr传递的成本

C++ 通过共享ptr传递的成本,c++,performance,shared-ptr,C++,Performance,Shared Ptr,我在整个应用程序中广泛使用std::tr1::shared_ptr。这包括将对象作为函数参数传入。考虑以下事项: class Dataset {...} void f( shared_ptr< Dataset const > pds ) {...} void g( shared_ptr< Dataset const > pds ) {...} ... 以及更换电话 shared_ptr< Dataset > pds( new Dataset(...) );

我在整个应用程序中广泛使用std::tr1::shared_ptr。这包括将对象作为函数参数传入。考虑以下事项:

class Dataset {...}

void f( shared_ptr< Dataset const > pds ) {...}
void g( shared_ptr< Dataset const > pds ) {...}
...
以及更换电话

shared_ptr< Dataset > pds( new Dataset(...) );
f( pds );
在我确信当程序流在f()内时对象不会被破坏的地方。但在我跑去更改一堆函数签名/调用之前,我想知道通过共享ptr传递的典型性能影响是什么。似乎shared_ptr不应该用于经常被调用的函数

如有任何意见,将不胜感激。谢谢你的阅读

-阿特姆

更新:在将一些函数更改为接受
常量数据集&
后,新配置文件如下所示:

Each sample counts as 0.01 seconds. % cumulative self self total time seconds seconds calls s/call s/call name 0.15 241.62 0.37 24981902 0.00 0.00 std::tr1::__shared_count::~__shared_count() 0.12 241.91 0.30 28342376 0.00 0.00 std::tr1::__shared_count::__shared_count(std::tr1::__shared_count const&) 每个样本计为0.01秒。 %累积自我总数 时间秒秒呼叫s/呼叫s/呼叫名称 0.15 241.62 0.37 24981902 0.00 0.00标准::tr1::\u共享\u计数::~\u共享\u计数() 0.12 241.91 0.30 28342376 0.00 0.00标准::tr1::_共享_计数::_共享_计数(标准::tr1::_共享_计数常数&)
我对析构函数调用的数量小于复制构造函数调用的数量感到有点困惑,但总体而言,我对相关运行时的减少感到非常满意。谢谢大家的建议。

听起来你真的知道自己在做什么。您已经分析了您的应用程序,并且您确切地知道在哪里使用了周期。您知道,只有不断地调用引用计数指针的构造函数才是昂贵的

我能给你的唯一提示是:假设在函数f(t*ptr)内部,如果你调用另一个使用共享指针的函数,然后你做other(ptr),other生成原始指针的共享指针。当第二个共享指针的引用计数达到0时,您实际上删除了您的对象…即使您不想这样做。你说过你经常使用引用计数指针,所以你必须小心类似的情况

编辑:
您可以将析构函数设置为私有的,并且只能是共享指针类的朋友,这样,析构函数只能由共享指针调用,这样您就安全了。不阻止从共享指针多次删除。根据Mat的评论。

始终通过const引用传递您的
共享\u ptr

void f(const shared_ptr<Dataset const>& pds) {...} 
void g(const shared_ptr<Dataset const>& pds) {...} 
void fn(shared_ptr< Dataset > pds)
{
   Dataset& ds = *pds;

   for (i = 0; i < 1000; ++i)
   {
      f(ds);
      g(ds);
   }
}
void f(const shared_ptr&pds){…}
void g(const shared_ptr&pds){…}
编辑:关于其他人提到的安全问题:

  • 当在整个应用程序中大量使用
    shared\u ptr
    时,传递值将占用大量时间(我看到它会占用50%以上的时间)
  • 当参数不应为空时,请使用
    const T&
    而不是
    const shared\u ptr&
  • 当性能是一个问题时,使用
    const shared\u ptr&
    const T*
    更安全

您只需将共享的ptr传递给函数/对象,这些函数/对象保留它以备将来使用。例如,某些类可能会保留共享的\u ptr,以便在工作线程中使用。对于简单的同步调用,使用普通指针或引用就足够了。共享ptr不应完全取代普通指针。

在性能关键型应用程序中,应避免任何对象创建和销毁,尤其是冗余对象创建和销毁

考虑一下共享ptr正在做什么。它不仅创建一个新对象并填充它,而且还引用共享状态以增加引用信息,而且对象本身可能完全存在于其他地方,这在缓存中会是噩梦

假设您需要共享的\u ptr(因为如果您可以处理一个本地对象,您就不会从堆中分配一个),但您甚至可以“缓存”共享的\u ptr取消引用的结果:

void f(const shared_ptr<Dataset const>& pds) {...} 
void g(const shared_ptr<Dataset const>& pds) {...} 
void fn(shared_ptr< Dataset > pds)
{
   Dataset& ds = *pds;

   for (i = 0; i < 1000; ++i)
   {
      f(ds);
      g(ds);
   }
}
void fn(共享数据集>pds)
{
数据集&ds=*pds;
对于(i=0;i<1000;++i)
{
f(ds);
g(ds);
}
}

…因为即使是*pds也需要比绝对必要的内存更多的内存。

如果您不使用,可以试一试吗?通过将引用计数和对象定位在同一内存区域中,您可能会看到与缓存一致性相关的性能提高。无论如何值得一试。

相关问题:相关问题:在某些平台上(如较旧的ARM),引用计数需要锁定互斥锁。这会使共享指针在实时环境中不可用(引用除外)。您是如何获得这些漂亮的基准数据的?@Daniel:这只是来自
gprof
。这就是我所做的-这里存在安全问题,但它们只是一些小问题。我宁愿有一个稍微慢一点的正确的应用程序,而不是一个死快的应用程序。您的测试应用程序是一个测试平台还是真正的代码?@pm100:请注意,我传递的是const引用,而不仅仅是引用,这可以防止大多数安全问题,同时提供显著的性能提升。当替代方法是传递共享_ptr的原始指针内容时,这种方法更安全。这是我最初的设计,但Fred链接的相关问题让我有点犹豫是否坚持使用它。尽管如此,对f()和g()的调用相当紧凑,我可以保证它们不会(直接或间接)重置pds。所以,我想问题是哪个更有效的void f(const-sharedptr&pds){…}还是void f(const-Dataset&pds){…}看起来区别仅仅在于解引用发生的位置:在f()的内部还是外部。@Artem:如果你的方法要求
pds
为非null,绝对喜欢
const数据集&
。如果null是有效值,则只需传递一个
共享\u ptr
。只是通过原始指针/ref(43min in)传递,除非你想存储它。你是想写f(ds)和g(ds)吗?我同意这一点
void fn(shared_ptr< Dataset > pds)
{
   Dataset& ds = *pds;

   for (i = 0; i < 1000; ++i)
   {
      f(ds);
      g(ds);
   }
}