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

时间:2022-11-14 13:29:58

This is the example:

这是例子:

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

And the output is:

和输出是:

ret=0
ret=5

Compiled with gcc 4.5.2, with and without -O2

与gcc 4.5.2一起编译,没有-O2。

Is this expected behavior?

这是预期行为吗?

Is this program data race free?

这个程序是免费的吗?

Thank you

谢谢你!

3 个解决方案

#1


69  

The constructor of std::thread deduces argument types and stores them by value.

std:::thread的构造函数演绎参数类型并按值存储它们。

C++ template function argument type deduction mechanism deduces type T from an argument of type T&. Hence, all arguments to std::thread are passed by value so that f1() and f2() always get a copy.

c++模板函数参数类型演绎机制从类型T的参数中演绎类型T。因此,std::线程的所有参数都通过值传递,因此f1()和f2()总是会得到一个副本。

If you insist on using a reference, wrap the argument using boost::ref() or std::ref():

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

thread t1(f1, boost::ref(ret));

Or, if you prefer simplicity, pass a pointer. This is what boost::ref() or std::ref() do for you behind the scene.

或者,如果您喜欢简单,请传递一个指针。这就是boost::ref()或std: ref()在后台为您做什么。

#2


6  

That you are required an explicit std::ref() (or boost::ref()) in these situations is actually a very useful safety feature as passing a reference can be by nature a dangerous thing to do.

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

With a non-const reference there is quite often a danger that you are passing in a local variable, with a const-reference it might be a temporary, and as you are creating a function to be called in a different thread (and with bind in general, often a function to be called later / in an asynchronous way) you will have the big danger of the object being no longer valid.

与non-const引用经常有危险你传入一个局部变量,常量引用可能是暂时的,当你在一个不同的线程创建一个函数被称为(通常和绑定在一般情况下,函数被称为后/以异步方式)你将有大危险的对象不再有效。

binding looks tidy but these bugs are the hardest to find, as where the error is caught (i.e. in calling the function) is not the same place that the error was made (at the time of binding) and it can be very hard to work out exactly which function is being called at the time, and therefore where it was bound.

绑定看起来整洁但最难找到这些错误,因为错误在哪里了(即在调用函数)是不一样的地方,错误的是(绑定)的时候,它可以很难准确计算出所调用的函数,因此绑定。

It is safe in your instance as you join the thread in the scope of the variable you are passing as reference. Therefore when you know that to be the case there is a mechanism for passing a reference.

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

It is not a feature of the language I would like to see changed, particularly as there is probably a lot of existing code relying on it making a copy that would break if it just took by reference automatically (and would then need an explicit way to force a copy).

它不是一个语言的功能我希望看到改变,尤其是可能是有很多现有的代码依赖于复制,将打破如果只是通过引用自动(将需要一个显式的方法来迫使一个副本)。

#3


5  

If you want to pass parameters by reference to a std::thread you must enclose each of them in std::ref:

如果您想通过引用std:::线程传递参数,您必须将每个参数包含在std:::ref:

thread t1(f1, std::ref(ret));

More info here.

更多的信息在这里。

#1


69  

The constructor of std::thread deduces argument types and stores them by value.

std:::thread的构造函数演绎参数类型并按值存储它们。

C++ template function argument type deduction mechanism deduces type T from an argument of type T&. Hence, all arguments to std::thread are passed by value so that f1() and f2() always get a copy.

c++模板函数参数类型演绎机制从类型T的参数中演绎类型T。因此,std::线程的所有参数都通过值传递,因此f1()和f2()总是会得到一个副本。

If you insist on using a reference, wrap the argument using boost::ref() or std::ref():

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

thread t1(f1, boost::ref(ret));

Or, if you prefer simplicity, pass a pointer. This is what boost::ref() or std::ref() do for you behind the scene.

或者,如果您喜欢简单,请传递一个指针。这就是boost::ref()或std: ref()在后台为您做什么。

#2


6  

That you are required an explicit std::ref() (or boost::ref()) in these situations is actually a very useful safety feature as passing a reference can be by nature a dangerous thing to do.

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

With a non-const reference there is quite often a danger that you are passing in a local variable, with a const-reference it might be a temporary, and as you are creating a function to be called in a different thread (and with bind in general, often a function to be called later / in an asynchronous way) you will have the big danger of the object being no longer valid.

与non-const引用经常有危险你传入一个局部变量,常量引用可能是暂时的,当你在一个不同的线程创建一个函数被称为(通常和绑定在一般情况下,函数被称为后/以异步方式)你将有大危险的对象不再有效。

binding looks tidy but these bugs are the hardest to find, as where the error is caught (i.e. in calling the function) is not the same place that the error was made (at the time of binding) and it can be very hard to work out exactly which function is being called at the time, and therefore where it was bound.

绑定看起来整洁但最难找到这些错误,因为错误在哪里了(即在调用函数)是不一样的地方,错误的是(绑定)的时候,它可以很难准确计算出所调用的函数,因此绑定。

It is safe in your instance as you join the thread in the scope of the variable you are passing as reference. Therefore when you know that to be the case there is a mechanism for passing a reference.

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

It is not a feature of the language I would like to see changed, particularly as there is probably a lot of existing code relying on it making a copy that would break if it just took by reference automatically (and would then need an explicit way to force a copy).

它不是一个语言的功能我希望看到改变,尤其是可能是有很多现有的代码依赖于复制,将打破如果只是通过引用自动(将需要一个显式的方法来迫使一个副本)。

#3


5  

If you want to pass parameters by reference to a std::thread you must enclose each of them in std::ref:

如果您想通过引用std:::线程传递参数,您必须将每个参数包含在std:::ref:

thread t1(f1, std::ref(ret));

More info here.

更多的信息在这里。