指针和引用之间的区别作为线程参数
这是一个例子:
#include<iostream> #include<thread> using namespace std; void f1(double& ret) { ret=5.; } void f2(double* ret) { *ret=5.; } int main() { double ret=0.; thread t1(f1, ret); t1.join(); cout << "ret=" << ret << endl; thread t2(f2, &ret); t2.join(); cout << "ret=" << ret << endl; }
输出是:
ret=0 ret=5
用gcc 4.5.2编译,有和没有-O2
这是预期的行为?
这个程序数据竞赛是免费的吗?
谢谢
std::thread
的构造函数会导出参数types并按值存储它们。
C ++模板函数参数types演绎机制从T&
types的参数中推导出typesT
因此, std::thread
所有参数都是按值传递的,所以f1()
和f2()
总是得到一个副本。
如果你坚持使用引用,使用boost::ref()
或std::ref()
来包装参数:
thread t1(f1, boost::ref(ret));
或者,如果你喜欢简单,传递一个指针。 这就是boost::ref()
或std::ref()
在场景后面做的事情。
在这些情况下,你需要一个明确的std::ref()
(或boost::ref()
)实际上是一个非常有用的安全特性,因为传递一个引用本质上是一个危险的事情。
使用非const引用常常会有一个危险,那就是你传入了一个局部variables,而const引用可能是一个临时variables,而且当你创build一个函数在另一个线程中被调用(并且绑定在一般情况下,往往是一个函数稍后/以asynchronous的方式调用),你将有很大的危险,对象不再有效。
绑定看起来很整洁,但这些错误是最难find的,因为错误被捕获的地方(即在调用函数中)与错误发生的位置不同(在绑定时),并且可能非常难以工作确切地说,当时正在调用哪个函数,并且因此在哪里被绑定。
在您作为参考传递的variables范围内join线程时,在您的实例中是安全的。 因此,当你知道这样的情况下有一个传递参考的机制。
这不是我想要改变的语言的一个特点,特别是因为可能有很多现有的代码依赖于它做一个副本,如果它只是通过引用自动引用会破坏(然后需要一个明确的方法来强制复制)。
如果你想通过引用std::thread
来传递参数,你必须把它们放在std::ref
:
thread t1(f1, std::ref(ret));
更多信息在这里 。