【发布时间】:2014-05-08 00:54:25
【问题描述】:
原帖(有错误)
我想包装对 std::thread 构造函数的调用(以跟踪所有正在运行的线程,以便我可以加入它们或做其他事情)。在此示例中,t1 线程构造正确,但t2 线程未使用 gcc 4.8.1。但是,在 Windows (VS2012) 上,它编译没有错误,运行也没有错误。根据here 的讨论,这可能看起来是 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;
}
这是编译器错误
-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
更新
我在这里问错了问题,准备删除它,但是因为答案很有帮助,所以我会留下它。问题是 Intel icpc 14.0 编译器(不是 gcc 4.8.1)是 throwing the same error regarding bind as discussed here。它与“包装器”无关,只是用成员函数而不是静态函数调用 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;
}
g++ (4.8.1) 的输出有效
-bash-4.1$ make CXX=g++
g++ -lpthread -std=c++11 main.cpp -o main
英特尔编译器 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$
【问题讨论】:
-
这是一个糟糕的包装。为什么要动态分配对象?!
-
您当前的 Wrapper 也在泄漏内存。您正在调用
new来创建线程对象,但您没有调用delete来释放内存。 -
不,这绝对是 Visual Studio 中的一个错误,与您提供的链接 100% 无关,这与
std::ref有关,而您的问题是关于线程复制构造函数。 -
@KerrekSB - 同意这是一个糟糕的包装器。这是一个不好的例子,但问题不在于内存泄漏,而是我无法使用
icpc构造 std::thread ,如图所示。