[英]In C++, How a std::thread can call a member function without creating an object?
If we have a class H
with some operator()
overloaded.如果我们有一个 class H
和一些operator()
重载。 How it is possible to create a thread from these member functions without instantiating an object from class H
.如何在不从 class H
实例化 object 的情况下从这些成员函数创建线程。 Consider the following code考虑以下代码
#include<iostream>
#include<thread>
class H {
public:
void operator()(){
printf("This is H(), I take no argument\n");
}
void operator()(int x){
printf("This is H(), I received %d \n",x);
}
};
int main(){
int param = 0xD;
//No object created
std::thread td_1 = std::thread(H());
std::thread td_2 = std::thread(H(),param);
td_1.join();
td_2.join();
//From an object
H h;
std::thread td_3 = std::thread(h);
std::thread td_4 = std::thread(h,param);
td_3.join();
td_4.join();
return 0;
}
produce the output:生成 output:
This is H(), I take no argument
This is H(), I received 13
This is H(), I take no argument
This is H(), I received 13
The question is, how td_1 and td_2 called the member function operator()
of class H
without an object of class H
?问题是,在没有 class H
的 object 的情况下,td_1 和 td_2 如何调用 class H
的成员 function operator()
?
how td_1 and td_2 called the member function operator() of class H without an object of class H? td_1 和 td_2 如何在没有 class H 的 object 的情况下调用 class H 的成员 function operator()?
td_1
and td_2
does create objects of type H
. td_1
和td_2
确实创建了H
类型的对象。 Those objects are temporaries.这些对象是临时的。 Next, those supplied function object (which are temporaries in this case) are moved/copied into the storage belonging to the newly created thread of execution and invoked from there.接下来,那些提供的function object (在这种情况下是临时的)被移动/复制到属于新创建的执行线程的存储中,并从那里调用。
You can confirm this by adding a default constructor and move constructor inside class H
as shown below:您可以通过添加默认构造函数并在 class H
内移动构造函数来确认这一点,如下所示:
#include<iostream>
#include<thread>
class H {
public:
void operator()(){
printf("This is H(), I take no argument\n");
}
void operator()(int x){
printf("This is H(), I received %d \n",x);
}
//default constructor
H()
{
std::cout<<"default constructor called"<<std::endl;
}
//move constructor
H(H&&)
{
std::cout<<"move constructor called"<<std::endl;
}
};
int main(){
int param = 0xD;
std::thread td_1 = std::thread(H());
std::thread td_2 = std::thread(H(),param);
td_1.join();
td_2.join();
return 0;
}
The output of the above program is:上述程序的output为:
default constructor called
move constructor called
move constructor called
default constructor called
move constructor called
move constructor called
This is H(), I take no argument
This is H(), I received 13
Consider this function:考虑这个 function:
void f() {
printf("This is f(), I take no argument\n");
}
A thread that calls the function is constructed like std::thread(f)
.调用 function 的线程的构造类似于std::thread(f)
。 Code like std::thread(f())
is invalid, because the parameter of std::thread
must be callable (in this case, a function object ).像std::thread(f())
这样的代码是无效的,因为std::thread
的参数必须是可调用的(在本例中是 function object )。 If you call the function before passing it to the constructor, std::thread
can no longer call it.如果在将其传递给构造函数之前调用 function, std::thread
将无法再调用它。
So you pass f
to the constructor, and it later becomes f()
, and the function is called.所以你将f
传递给构造函数,它后来变成f()
,然后调用 function 。
Similar to passing the name of a function, you can pass an object to the constructor, and the thread later calls operator()
.类似于传递 function 的名称,您可以将 object 传递给构造函数,然后线程稍后调用operator()
。 When you write std::thread(H())
, you construct a temporary object. Because class H
has operator()
, this code is accepted.当你写std::thread(H())
时,你构造了一个临时的 object。因为 class H
有operator()
,这个代码被接受。
In fact, std::thread(H{})
is also accepted.事实上, std::thread(H{})
也被接受。 This shows that the parentheses refer to the constructor H::H()
, rather than H::operator()
.这表明括号指的是构造函数H::H()
,而不是H::operator()
。 You did not write a constructor for the class, but the compiler creates a default constructor.您没有为 class 编写构造函数,但编译器创建了默认构造函数。
You could also use this code to construct a temporary object with H()
and immediately call operator()
:您还可以使用此代码构造一个带有H()
的临时 object 并立即调用operator()
:
int main() {
H()(); // Valid: H() is callable
//f()(); // Invalid: f() is not callable
}
The syntax H()
is creating a temporary object of type H
in this context.语法H()
在此上下文中创建类型为H
的临时 object。 The temporary object is passed to the std::thread
constructor.临时 object 被传递给std::thread
构造函数。
Now, if the thread were to call operator()
on that temporary, that would be a problem, since the temporary will only live until the end of the line std::thread td_1 = std::thread(H());
现在,如果线程要在该临时对象上调用operator()
,那将是一个问题,因为临时对象只会存在到该行的末尾std::thread td_1 = std::thread(H());
and the thread function may execute after that.然后线程 function 可能会执行。
However, the thread doesn't actually use that temporary.但是,线程实际上并没有使用那个临时的。 Instead a new object of the (decayed) argument type is created for the thread, copied/moved from the temporary object you gave to the constructor.相反,为线程创建了一个新的 object(已衰减)参数类型,从您提供给构造函数的临时 object 复制/移动。 This H
object lives until the thread exits and on this object operator()
is called.这个H
object 一直存在,直到线程退出并且在这个 object 上调用operator()
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.