通过const引用传递shared_pointer是threadsave吗?

Is it threadsave to pass shared_pointer by const reference?

我经常读到我应该通过 const 引用将 shared_ptr 传递给一个函数,因为它更快。当我想到它时,我不确定这是否是一个真正好的建议,因为我不确定这是否会节省线程。谁能告诉我这是否可以通过 const ref 传递线程?

使用 & 您可以获得对象本身。

你没有增加引用计数,你只是传递了它自己的对象。人们建议通过 const& 的原因是为了避免线程安全地增加引用计数的成本。作为 const& 传递的成本与复制 int 或指针的成本相同,并且不会将临时对象绑定到 const&,因为 shared_ptr 的构造函数被标记为 explicit.

并且因为您始终至少有 1 个对象引用(引用从被调用函数绑定到的对象),所以不用担心在使用本地引用时对象可能会被销毁。

通过 const 引用传递与线程无关。看下面的简单代码:

void foo(const std::shared_ptr<int>& x) {
    sleep(100000);
}


void bar() {
    //...
    std::shared_ptr y = ...;
    foo(y);
}

y 将在 foo returns 之前一直存在于酒吧中 - 从而确保 shared_ptr 仍然有效。如果 foo() 要创建另一个线程并将 x 传递给它,它将必须复制它 - 这将增加引用计数器。

无论传递什么对象,通过引用传递始终是线程安全的。如果它是对 const 的引用则无关紧要。

您应该更喜欢通过 const& 以避免复制任何 class 的开销。例如,这对于 std::string.

之类的内容尤为重要

const& 传递 shared_ptr 的情况下,开销主要是 incrementing and decrementing of the reference count 因为它是原子的。

但是!使用 const& shared_ptr 创建线程时有一个陷阱:引用计数将递增。因为它是递增的,所以几乎就像您按值传递它一样。实际上,您是按值传递给 std::thread 构造函数,因此是增量,然后按引用传递给函数。

自己看看:

// gcc (Ubuntu 4.8.4-2ubuntu1~14.04.1) 4.8.4
void test(const shared_ptr<int>& i)
{
  cout << "c = " << i.use_count() << endl;
}

int main(int argc, char** argv)
{
 shared_ptr<int> i(new int);
 cout << "c = " << i.use_count() << endl;
 test(i);

 cout << "thread!" << endl;
 thread t(test, i);
 t.join();
 cout << "c = " << i.use_count() << endl;
}

结果为:

c = 1
c = 1
thread!
c = 2 // <= incremented!
c = 1 // <= thread joined!

shared_ptr 是线程安全的完美候选者,但它不会保护您免受竞争条件和死锁的影响。