当一个函数接受一个shared_ptr(来自boost或c++ 11 STL)时,你是否传递它:

foo(const shared_ptr<T>& p) 或通过值:void foo(shared_ptr<T> p) ?

我更喜欢第一种方法,因为我怀疑它会更快。但这真的值得吗,还有其他问题吗?

你能否给出你选择的原因,或者如果是这样,为什么你认为这无关紧要。


当前回答

Scott、Andrei和Herb在c++ and Beyond 2011的Ask Us Anything会议上讨论并回答了这个问题。从4:34开始观看shared_ptr的性能和正确性。

简单地说,没有理由按值传递,除非目标是共享对象的所有权(例如:共享对象的所有权)。不同的数据结构之间,或不同的线程之间)。

除非你可以像Scott Meyers在上面链接的演讲视频中解释的那样对它进行移动优化,但这与你可以使用的实际c++版本有关。

这个讨论的主要更新发生在GoingNative 2012会议的互动小组:问我们任何事情!值得一看,尤其是22:50开始。

其他回答

就我个人而言,我会使用const引用。没有必要为了函数调用而增加引用计数。

从c++ 11开始,你应该比你想象的更经常地通过值而不是参数来使用它。

如果您正在使用std::shared_ptr(而不是底层类型T),那么您这样做是因为您想对它做一些事情。

If you would like to copy it somewhere, it makes more sense to take it by copy, and std::move it internally, rather than taking it by const& and then later copying it. This is because you allow the caller the option to in turn std::move the shared_ptr when calling your function, thus saving yourself a set of increment and decrement operations. Or not. That is, the caller of the function can decide whether or not he needs the std::shared_ptr around after calling the function, and depending on whether or not move or not. This is not achievable if you pass by const&, and thus it is then preferably to take it by value.

当然,如果调用者需要更长的时间使用他的shared_ptr(因此不能std::移动它),并且你不想在函数中创建一个纯副本(比如你想要一个弱指针,或者你只是有时想要复制它,这取决于某些条件),那么const&可能仍然是更可取的。

例如,你应该这样做

void enqueue(std::shared<T> t) m_internal_queue.enqueue(std::move(t));

over

void enqueue(std::shared<T> const& t) m_internal_queue.enqueue(t);

因为在这种情况下,您总是在内部创建一个副本

Scott、Andrei和Herb在c++ and Beyond 2011的Ask Us Anything会议上讨论并回答了这个问题。从4:34开始观看shared_ptr的性能和正确性。

简单地说,没有理由按值传递,除非目标是共享对象的所有权(例如:共享对象的所有权)。不同的数据结构之间,或不同的线程之间)。

除非你可以像Scott Meyers在上面链接的演讲视频中解释的那样对它进行移动优化,但这与你可以使用的实际c++版本有关。

这个讨论的主要更新发生在GoingNative 2012会议的互动小组:问我们任何事情!值得一看,尤其是22:50开始。

我运行下面的代码,一次用foo通过const&获取shared_ptr,另一次用foo通过value获取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;
}

使用VS2015, x86发布版本,在我的英特尔酷睿2四(2.4GHz)处理器上

const shared_ptr&     - 10ms  
shared_ptr            - 281ms 

按值复制的版本慢了一个数量级。 如果你从当前线程同步调用一个函数,最好使用const&版本。

众所周知,通过值传递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的引用是不行的。

将共享对象传递给工作线程也是如此。