简体   繁体   English

在 C++ 中,std::thread 如何在不创建 object 的情况下调用成员 function?

[英]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_1td_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 Hoperator() ,这个代码被接受。

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM