通过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
是线程安全的完美候选者,但它不会保护您免受竞争条件和死锁的影响。
我经常读到我应该通过 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
是线程安全的完美候选者,但它不会保护您免受竞争条件和死锁的影响。