指针和引用之间的差异作为线程参数

Pre*_*rag 38 c++ multithreading reference c++11 stdthread

这是一个例子:

#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;   
}
Run Code Online (Sandbox Code Playgroud)

输出是:

ret=0
ret=5
Run Code Online (Sandbox Code Playgroud)

用gcc 4.5.2编译,有和没有-O2标志.

这是预期的行为吗?

这个节目数据是否免费比赛?

谢谢

Max*_*kin 85

构造函数std::thread推导出参数类型并按值存储它们的副本.这需要确保参数对象的生命周期至少与线程的生命周期相同.

C++模板函数参数类型推导机制T从类型的参数中推导出类型T&.所有参数std::thread被复制,然后传递给线程函数,以便 f1()f2()总是使用该副本.

如果您坚持使用引用,请使用boost::ref()或包装参数std::ref():

thread t1(f1, boost::ref(ret));
Run Code Online (Sandbox Code Playgroud)

或者,如果您更喜欢简单,请传递指针.这是你在场后的表现boost::ref()std::ref()做法.

  • @patrik与存储引用或指针相比,值语义(复制)是安全的.当引用的对象被破坏时,引用或指针可能会悬空.这就是为什么`std :: bind`和`std :: thread`默认按值存储参数,你必须明确要求它做一个不太安全的事情. (2认同)

Cas*_*Cow 9

在这些情况下你需要一个明确的std::ref()(或boost::ref())实际上是一个非常有用的安全功能,因为传递引用本质上是一件危险的事情.

使用非const引用时,通常存在传递局部变量的危险,使用const引用它可能是临时的,并且当您创建要在不同线程中调用的函数时(并且使用bind)通常,通常是稍后/以异步方式调用的函数),您将面临对象不再有效的巨大危险.

绑定看起来整洁,但这些错误是最难找到的,因为错误被捕获(即在调用函数时)与错误发生的位置不同(在绑定时)并且可能非常难以工作确切地说当时正在调用哪个函数,因此它被绑定的位置.

在您作为参考传递的变量范围内加入线程时,在您的实例中是安全的.因此,当您知道是这种情况时,有一种传递引用的机制.

它不是我希望看到的语言的一个特征,特别是因为很可能有很多现有的代码依赖于它制作一个副本,如果它只是通过引用自动进行就会破坏(然后需要一个明确的方法来强制复制).


Mat*_*lia 8

如果要通过引用传递参数,则std::thread必须将每个参数括在std::ref:

thread t1(f1, std::ref(ret));
Run Code Online (Sandbox Code Playgroud)

更多信息在这里.