如何包装对`std :: thread`构造函数的调用?(适用于gcc,VS和icpc)

Mar*_*ata 3 c++ icc c++11 stdthread

原帖(有错误)

我想包装一个对std :: thread构造函数的调用(以跟踪所有运行的线程,以便我可以加入它们或做其他事情).在此示例中,t1线程正确构造,但t2线程不使用gcc 4.8.1.但是,在Windows(VS2012)上,它编译时没有错误,并且运行没有错误.基于此处的讨论,这似乎是gcc中的一个错误,但可以说它实际上是VS中的一个错误.这样做的正确方法是什么?

#include <iostream>
#include <thread>

class A {
public:
    void foo(int n ) { std::cout << n << std::endl; }
};

template<class F, class Arg>
std::thread& wrapper(F&& f, Arg&& a)
{
   std::thread* t = new std::thread(f,a,100);
   return *t;
}

int main()
{
    A a;

    std::thread t1(&A::foo, &a, 100);
    t1.join();

    std::thread t2 = wrapper(&A::foo, &a);
    t2.join();

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

这是编译器错误

-bash-4.1$ make
g++ -std=c++11    main.cpp   -o main
main.cpp: In function ‘int main()’:
main.cpp:23:41: error: use of deleted function ‘std::thread::thread(std::thread&)’
     std::thread t2 = wrapper(&A::foo, &a);
                                         ^
In file included from main.cpp:2:0:
/opt/rh/devtoolset-2/root/usr/include/c++/4.8.1/thread:125:5: error: declared here
     thread(thread&) = delete;
     ^
make: *** [all] Error 1
Run Code Online (Sandbox Code Playgroud)

更新

我在这里问了一个错误的问题并准备将其删除,但由于答案很有帮助,我会离开它.问题是英特尔icpc 14.0编译器(不是gcc 4.8.1)引发了与bind此处讨论的相同的错误.它与"包装器"无关,只是用成员函数而不是静态函数调用std :: thread.

关于内存泄漏的投诉是100%有效的,但那是我对该示例进行了不幸的简化(来自我的真实代码).实际代码将线程保存在容器中,并在销毁时删除线程.

这是一个更好的例子:

#include <iostream>
#include <thread>

class A {
public:
    void foo() { }

    template<class Function, class Arg>
    std::thread* wrapper(Function&& f, Arg&& a)
    {
        auto t = new std::thread(f,a);
        return t;
    }
};

int main()
{
    A a;

    std::thread t1(&A::foo, &a);
    t1.join();

    std::thread* t2 = a.wrapper(&A::foo, &a);
    t2->join();
    delete t2;

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

并且g++(4.8.1)的输出有效

-bash-4.1$ make CXX=g++
g++ -lpthread -std=c++11    main.cpp   -o main
Run Code Online (Sandbox Code Playgroud)

和英特尔编译器icpc(14.0)的输出不起作用

-bash-4.1$ make CXX=icpc
icpc -lpthread -std=c++11    main.cpp   -o main
/opt/rh/devtoolset-2/root/usr/include/c++/4.8.1/functional(1697): error: class "std::result_of<std::_Mem_fn<void (A::*)()> (A *)>" has no member "type"
        typedef typename result_of<_Callable(_Args...)>::type result_type;
                                                         ^
          detected during:
            instantiation of class "std::_Bind_simple<_Callable (_Args...)> [with _Callable=std::_Mem_fn<void (A::*)()>, _Args=<A *>]" at line 1753
            instantiation of "std::_Bind_simple_helper<_Callable, _Args...>::__type std::__bind_simple(_Callable &&, _Args &&...) [with _Callable=void (A::*)(), _Args=<A *>]" at line 137 of "/opt/rh/devtoolset-2/root/usr/include/c++/4.8.1/thread"
            instantiation of "std::thread::thread(_Callable &&, _Args &&...) [with _Callable=void (A::*)(), _Args=<A *>]" at line 20 of "main.cpp"

/opt/rh/devtoolset-2/root/usr/include/c++/4.8.1/functional(1726): error: class "std::result_of<std::_Mem_fn<void (A::*)()> (A *)>" has no member "type"
          typename result_of<_Callable(_Args...)>::type
                                                   ^
          detected during:
            instantiation of class "std::_Bind_simple<_Callable (_Args...)> [with _Callable=std::_Mem_fn<void (A::*)()>, _Args=<A *>]" at line 1753
            instantiation of "std::_Bind_simple_helper<_Callable, _Args...>::__type std::__bind_simple(_Callable &&, _Args &&...) [with _Callable=void (A::*)(), _Args=<A *>]" at line 137 of "/opt/rh/devtoolset-2/root/usr/include/c++/4.8.1/thread"
            instantiation of "std::thread::thread(_Callable &&, _Args &&...) [with _Callable=void (A::*)(), _Args=<A *>]" at line 20 of "main.cpp"

compilation aborted for main.cpp (code 2)
make: *** [all] Error 2
-bash-4.1$
Run Code Online (Sandbox Code Playgroud)

Ker*_* SB 5

你的包装应该是这样的:

template<class F, class Arg>
std::thread wrapper(F&& f, Arg&& a)
{
    return std::thread(std::forward<F>(f), std::forward<Arg>(a));
}
Run Code Online (Sandbox Code Playgroud)