在 C++11 中通过引用 std::thread 传递对象

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/34078208/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 14:20:20  来源:igfitidea点击:

Passing object by reference to std::thread in C++11

c++multithreadingc++11pass-by-referencestdthread

提问by austinmarton

Why can't you pass an object by reference when creating a std::thread?

为什么在创建对象时不能通过引用传递对象std::thread

For example the following snippit gives a compile error:

例如,以下代码段给出了编译错误:

#include <iostream>
#include <thread>

using namespace std;

static void SimpleThread(int& a)  // compile error
//static void SimpleThread(int a)     // OK
{
    cout << __PRETTY_FUNCTION__ << ":" << a << endl;
}

int main()
{
    int a = 6;

    auto thread1 = std::thread(SimpleThread, a);

    thread1.join();
    return 0;
}

Error:

错误:

In file included from /usr/include/c++/4.8/thread:39:0,
                 from ./std_thread_refs.cpp:5:
/usr/include/c++/4.8/functional: In instantiation of ‘struct std::_Bind_simple<void (*(int))(int&)>':
/usr/include/c++/4.8/thread:137:47:   required from ‘std::thread::thread(_Callable&&, _Args&& ...) [with _Callable = void (&)(int&); _Args = {int&}]'
./std_thread_refs.cpp:19:47:   required from here
/usr/include/c++/4.8/functional:1697:61: error: no type named ‘type' in ‘class std::result_of<void (*(int))(int&)>'
       typedef typename result_of<_Callable(_Args...)>::type result_type;
                                                             ^
/usr/include/c++/4.8/functional:1727:9: error: no type named ‘type' in ‘class std::result_of<void (*(int))(int&)>'
         _M_invoke(_Index_tuple<_Indices...>)
         ^

I've changed to passing a pointer, but is there a better work around?

我已改为传递指针,但有更好的解决方法吗?

回答by ShadowRanger

Explicitly initialize the thread with a reference_wrapperby using std::ref:

明确初始化一个线程reference_wrapper使用std::ref

auto thread1 = std::thread(SimpleThread, std::ref(a));

(or std::crefinstead of std::ref, as appropriate). Per notes from cppreference on std:thread:

(或std::cref代替std::ref,视情况而定)。根据cppreference 上的std:thread注释:

The arguments to the thread function are moved or copied by value. If a reference argument needs to be passed to the thread function, it has to be wrapped (e.g. with std::refor std::cref).

线程函数的参数按值移动或复制。如果需要将引用参数传递给线程函数,则必须对其进行包装(例如使用std::refstd::cref)。

回答by u8012646

Based on this comment, this answer elaborates on the reason why the arguments are not passed by referenceto the thread function by default.

基于此评论,此答案详细说明了默认情况下不通过引用传递给线程函数的参数的原因。

Consider the following function SimpleThread():

考虑以下函数SimpleThread()

void SimpleThread(int& i) {
    std::this_thread::sleep_for(std::chrono::seconds{1});
    i = 0;
}

Now, imagine what would happenif the following code compiled (it does notcompile):

现在,想象一下会发生,如果下面的代码编译(它并没有编译):

int main()
{
    {
        int a;
        std::thread th(SimpleThread, a);
        th.detach();
    }
    // "a" is out of scope
    // at this point the thread may be still running
    // ...
}

The argument awould be passedby reference to SimpleThread(). The thread may still be sleeping in the function SimpleThread()after the variable ahas already gone out of scope and its lifetime has ended. If so, iin SimpleThread()would actually be a dangling reference, and the assignment i = 0would result in undefined behaviour.

参数a将通过引用传递SimpleThread()SimpleThread()在变量a已经超出范围并且其生命周期结束后,线程可能仍在函数中休眠。如果是这样,iinSimpleThread()实际上将是一个悬空引用,并且赋值i = 0将导致未定义的行为

By wrapping reference arguments with the class template std::reference_wrapper(using the function templates std::refand std::cref) you explicitly express your intentions.

通过使用类模板std::reference_wrapper(使用函数模板std::refstd::cref)包装引用参数,您可以明确表达您的意图。