当一个函数接受shared_ptr(来自boost或c++ 11 STL)时,你是否将它传递:
shared_ptr
通过const引用:void foo(const shared_ptr<T>& p)
void foo(const shared_ptr<T>& p)
或通过值:void foo(shared_ptr<T> p) ?
void foo(shared_ptr<T> p)
我更喜欢第一种方法,因为我怀疑它会更快。但这真的值得吗,还有其他问题吗?
你能否给出你选择的原因,或者如果是这样,为什么你认为这无关紧要。
就我个人而言,我会使用const引用。没有必要为了函数调用而增加引用计数。
const
通过const引用传递,它更快。如果你需要存储它,比如在某个容器中,引用计数将通过复制操作自动神奇地增加。
Shared_ptr不够大,它的构造函数\析构函数也没有做足够的工作,因此拷贝有足够的开销来关心按引用传递和按复制传递的性能。
这个问题已经由Scott, Andrei和Herb在c++和超越2011年的问我们任何问题会议上讨论和回答了。从4:34 shared_ptr的性能和正确性观看。
简单地说,没有理由按值传递,除非目标是共享对象的所有权(例如。不同的数据结构之间,或不同的线程之间)。
除非你可以像Scott Meyers在上面链接的演讲视频中解释的那样对它进行移动优化,但这与你可以使用的实际c++版本有关。
这个讨论的主要更新发生在GoingNative 2012会议的互动面板:问我们任何问题!上,值得关注,特别是来自22:50。
这是赫伯·萨特的观点
不要将智能指针作为函数参数传递,除非 您希望使用或操作智能指针本身,例如to .共享或转让所有权 指南:表示函数将存储和共享函数的所有权 使用按值shared_ptr参数的堆对象。< / p > 指南:使用a non-const shared_ptr&参数只能修改shared_ptr. properties参数。使用一个 const shared_ptr&只有在你不确定是否 并不是说你会拿到一份复印件并拥有一部分所有权;否则使用小部件* 反之(如果不是空的,则是一个widget&)
指南:表示函数将存储和共享函数的所有权 使用按值shared_ptr参数的堆对象。< / p >
指南:使用a non-const shared_ptr&参数只能修改shared_ptr. properties参数。使用一个 const shared_ptr&只有在你不确定是否 并不是说你会拿到一份复印件并拥有一部分所有权;否则使用小部件* 反之(如果不是空的,则是一个widget&)
我运行下面的代码,一次用foo通过const&获取shared_ptr,另一次用foo按值获取shared_ptr。
foo
const&
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; }
使用VS2015, x86发布版本,在我的英特尔酷睿2四(2.4GHz)处理器上
const shared_ptr& - 10ms shared_ptr - 281ms
按值拷贝的版本慢了一个数量级 如果你从当前线程同步调用一个函数,最好使用const&版本
由于不知道shared_copy复制操作的时间成本,我遇到了更高的CPU使用问题。我从来没有想到原子增量和减量会付出这么大的代价。
根据我的测试结果,int32原子增量和减量比非原子增量和减量需要2倍或40倍的时间。我用的是3GHz Core i7, Windows 8.1。前者在不发生争用时得出,后者在发生争用可能性较大时得出。我始终牢记原子操作是基于硬件的锁。锁就是锁。发生争用时对性能不利。
遇到这种情况,我总是使用byref(const shared_ptr&)而不是byval(shared_ptr)。
从c++ 11开始,你应该比你想象的更频繁地使用按价值除以价值;。
如果您正在使用std::shared_ptr(而不是底层类型T),那么您这样做是因为您想对它做一些事情。
如果你想在某个地方使用复制它,通过复制和std::在内部移动它会更有意义,而不是通过const&然后再复制。这是因为您允许调用方在调用函数时依次std::移动shared_ptr,从而节省了一组递增和递减操作。与否。也就是说,函数的调用者可以在调用函数后决定是否需要std::shared_ptr,这取决于是否移动。这是不可能实现的,如果你通过const&,因此,最好是采取它的价值。
当然,如果调用者需要更长的时间使用他的shared_ptr(因此不能std::移动它),并且你不想在函数中创建一个普通的副本(比如你想要一个弱指针,或者你只是有时想要复制它,这取决于某些条件),那么const&可能还是更可取的。
例如,你应该这样做
void enqueue(std::shared<T> t) m_internal_queue.enqueue(std::move(t));
在
void enqueue(std::shared<T> const& t) m_internal_queue.enqueue(t);
因为在这种情况下,您总是在内部创建一个副本
最近有一篇博客:https://medium.com/@vgasparyan1995/pass-by-value-vs-pass-by-reference-to-const-c-f8944171e3ce
const shared_ptr<T>&
基本上,唯一合理的参数类型是:
shared_ptr<T>
shared_ptr<const T>
T&
const T&
T
正如@accel在https://stackoverflow.com/a/26197326/1930508中指出的那样,Herb Sutter的建议是:
使用const shared_ptr&只有当你不确定是否要拷贝和共享所有权时,才可以作为参数
但有多少情况下你不确定?所以这种情况很少见
众所周知,通过值传递shared_ptr是有代价的,应该尽可能避免。
通过shared_ptr的代价
大多数情况下,通过引用传递shared_ptr,甚至更好的是通过const引用。
cpp核心准则有一个传递shared_ptr的特定规则
R。34:采用shared_ptr参数表示函数是部分所有者
void share(shared_ptr<widget>); // share -- "will" retain refcount
当调用方将一个共享对象传递给异步被调用方时,即调用方在被调用方完成其工作之前就超出了作用域,这就是按值传递shared_ptr确实必要的一个例子。被调用方必须通过取share_ptr值来“延长”共享对象的生存期。在这种情况下,传递对shared_ptr的引用是不行的。
将共享对象传递给工作线程也是如此。