C++ 指针和引用作为线程参数的区别
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5116756/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Difference between pointer and reference as thread parameter
提问by Predrag
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
flag.
用 gcc 4.5.2 编译,带和不带-O2
标志。
Is this expected behavior?
这是预期的行为吗?
Is this program data race free?
这个程序数据竞争免费吗?
Thank you
谢谢
回答by Maxim Egorushkin
The constructor of std::thread
deduces argument types and stores copies of them by value. This is needed to ensure the lifetime of the argument object is at least the same as that of the thread.
的构造函数std::thread
推导出参数类型并按值存储它们的副本。这需要确保参数对象的生命周期至少与线程的生命周期相同。
C++ template function argument type deduction mechanism deduces type T
from an argument of type T&
. All arguments to std::thread
are copied and then passed to the thread function so that f1()
and f2()
always use that copy.
C++ 模板函数参数类型推导机制T
从type的参数推导类型T&
。所有参数std::thread
都被复制,然后传递给线程函数,以便 f1()
并f2()
始终使用该副本。
If you insist on using a reference, wrap the argument using boost::ref()
or std::ref()
:
如果您坚持使用引用,请使用boost::ref()
or包装参数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()
为您做什么。
回答by Matteo Italia
回答by CashCow
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.
对于非常量引用,通常存在传递局部变量的危险,对于常量引用,它可能是临时的,并且当您创建要在不同线程中调用的函数时(并且使用 bind通常,通常是稍后/以异步方式调用的函数)您将面临对象不再有效的巨大危险。
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).
这不是我希望看到改变的语言的一个特性,特别是因为可能有很多现有的代码依赖它制作一个副本,如果它只是通过引用自动获取就会破坏(然后需要一种明确的方式来强制复制)。