C++ 我们应该通过引用还是通过值传递共享的\u ptr?
当函数接受一个C++ 我们应该通过引用还是通过值传递共享的\u ptr?,c++,c++11,boost,shared-ptr,C++,C++11,Boost,Shared Ptr,当函数接受一个共享\u ptr(来自boost或C++11 STL)时,您是否传递它: 按常量参考:void foo(常量共享\u ptr&p) 或按值:void foo(共享) 我更喜欢第一种方法,因为我怀疑它会更快。但这真的值得吗?或者还有其他问题吗 请给出您选择的原因,或者如果是这种情况,为什么您认为这无关紧要。我个人会使用const参考。无需为了函数调用而增加引用计数以再次减少它。通过constreference,速度更快。如果您需要将其存储在某个容器中,则复制操作会自动神奇地增加引
共享\u ptr
(来自boost或C++11 STL)时,您是否传递它:
- 按常量参考:
void foo(常量共享\u ptr&p)
- 或按值:
void foo(共享)
请给出您选择的原因,或者如果是这种情况,为什么您认为这无关紧要。我个人会使用
const
参考。无需为了函数调用而增加引用计数以再次减少它。通过const
reference,速度更快。如果您需要将其存储在某个容器中,则复制操作会自动神奇地增加引用计数。共享\u ptr不够大,它的构造函数\析构函数也没有做足够的工作,以使副本产生足够的开销,从而关心通过引用传递与通过副本传递的性能。Scott、Andrei和Herb在的会话中讨论并回答了这个问题。从4点34分开始看
简而言之,没有理由按值传递,除非目标是共享对象的所有权(例如,在不同的数据结构之间,或在不同的线程之间)
除非你能在上面的谈话视频中解释Scott Meyers的优化,但是这与C++的实际版本有关,你可以使用.< 这次讨论的一个重要更新发生在会议期间,值得一看,特别是从
指导原则:不要将智能指针作为函数参数传递,除非 您希望使用或操作智能指针本身,例如 分享或转让所有权 准则:表示函数将存储和共享 使用by value shared_ptr参数的堆对象 准则:使用 non-const shared_ptr&仅用于修改共享_ptr的参数。使用 const shared_ptr&仅当您不确定是否 不,你会复制并分享所有权;否则,请使用小部件* 取而代之的是(如果不可为null,则为小部件&)我运行下面的代码,一次使用
foo
通过const&
获取shared\u ptr
,另一次使用foo
通过值获取shared\u ptr
void foo(const std::shared_ptr<int>& p)
{
static int x = 0;
*p = ++x;
}
int main()
{
auto p = std::make_shared<int>();
auto start = clock();
for (int i = 0; i < 10000000; ++i)
{
foo(p);
}
std::cout << "Took " << clock() - start << " ms" << std::endl;
}
按值复制版本的速度慢了一个数量级。如果您从当前线程同步调用函数,请选择
const&
版本。不知道原子增量和减量所在的共享拷贝操作的时间成本,我遇到了更高的CPU使用率问题。我从来没想到原子的增量和减量会花费这么多的成本
根据我的测试结果,int32原子增量和减量比非原子增量和减量要花费2到40倍。我在Windows8.1的3GHz CoreI7上得到了它。前者在没有发生争用时产生,后者在发生争用的可能性很高时产生。我要记住,原子操作最终是基于硬件的锁。锁就是锁。发生争用时会对性能造成不良影响
经历了这种情况,我总是使用byref(const shared_ptr&)而不是byval(shared_ptr&)。因为C++11,你应该比你想象的更频繁地使用它 如果您使用std::shared_ptr(而不是底层类型T),那么您这样做是因为您想用它做点什么 如果您想在某个地方复制它,那么通过复制和std::在内部移动它会更有意义,而不是通过const&然后再复制它。这是因为您允许调用者在调用函数时依次选择std::move shared_ptr,从而节省了一组递增和递减操作。或者不是。也就是说,函数的调用方可以在调用函数后决定是否需要std::shared_ptr,这取决于是否移动。如果通过常量&,这是不可能实现的,因此最好通过值来获取它
void foo(const std::shared_ptr<int>& p)
{
static int x = 0;
*p = ++x;
}
int main()
{
auto p = std::make_shared<int>();
auto start = clock();
for (int i = 0; i < 10000000; ++i)
{
foo(p);
}
std::cout << "Took " << clock() - start << " ms" << std::endl;
}
当然,如果调用方都需要其共享的ptr存在更长的时间(因此无法std::move它),并且您不想在函数中创建普通副本(比如您想要弱指针,或者您只是有时想要复制它,这取决于某些条件),那么const&可能仍然是更好的选择
例如,你应该这样做
void enqueue(std::shared<T> t) m_internal_queue.enqueue(std::move(t));
void排队(std::shared t)m_internal_queue.enqueue(std::move(t));
结束
void排队(std::shared const&t)m_internal_queue.enqueue(t);
因为在这种情况下,您总是在内部创建副本最近有一篇博文: 所以答案是:不要(几乎)路过
constshared\u ptr&
只需传递基础类即可 基本上,唯一合理的参数类型是:
-修改并获得所有权共享\u ptr
-不修改,拥有所有权共享\u ptr
-修改,无所有权T&
-不修改,没有所有权const T&
-不修改,没有所有权,复制成本低T
但有多少情况你不确定?所以这是一种罕见的情况众所周知,按值传递共享的ptr是有成本的,如果可能的话应该避免 大多数情况下,通过引用传递共享_ptr,甚至通过const引用传递更好 cpp核心指南对通过共享ptr有一个特定规则
无效共享(shar)
void enqueue(std::shared<T> const& t) m_internal_queue.enqueue(t);
void share(shared_ptr<widget>); // share -- "will" retain refcount