[英]Difference between pointer and reference as thread parameter
这是示例:
#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
的构造函数推导参数类型并按值存储它们的副本。 这需要确保自变量对象的生存期至少与线程的生存期相同。
C ++模板函数参数类型推导机制从类型T&
的参数推导类型T
复制std::thread
所有参数,然后将其传递给线程函数,以便f1()
和f2()
始终使用该副本。
如果您坚持使用引用,请使用boost::ref()
或std::ref()
包装参数:
thread t1(f1, boost::ref(ret));
或者,如果您更喜欢简单性,请传递一个指针。 这就是boost::ref()
或std::ref()
在幕后为您做的事情。
在这种情况下,您需要显式的std::ref()
(或boost::ref()
)实际上是非常有用的安全功能,因为传递引用本质上是一件危险的事情。
使用非const引用时,通常存在传递本地变量的危险,使用const引用时,它可能是临时的,并且在创建要在其他线程中调用的函数时(以及使用bind时)通常,通常是一个以后要用异步方式调用的函数),您将面临对象不再有效的巨大危险。
绑定看起来很整洁,但是这些错误是最难发现的,因为捕获错误的位置(即调用函数)与发生错误的位置不同(绑定时),并且很难处理确切地指出当时正在调用哪个函数,以及它的绑定位置。
在将线程作为引用传递的变量范围内加入线程时,在您的实例中是安全的。 因此,当您知道这种情况时,就有一种传递引用的机制。
这不是我希望看到的语言功能的变化,特别是因为可能有很多现有代码依赖它来制作副本,如果仅自动引用它就会破坏副本(然后需要一种明确的方式来实现)强制复制)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.