指针和引用之间的区别作为线程参数

这是一个例子:

#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)); 

更多信息在这里 。