简体   繁体   English

std :: thread,类构造函数和析构函数

[英]std::thread, class constructor and destructor

When testing threads in C++11 I have created the following example: 在C ++ 11中测试线程时,我创建了以下示例:

#include <iostream>
#include <thread>

class Foo {
public:
    Foo(void) {
        std::cout << "Constructor called: " << this << std::endl;
    }
    ~Foo(void) {
        std::cout << "Destructor called: " << this << std::endl;
    }
    void operator()() const {
        std::cout << "Operatior called: " << this << std::endl;
    }
};

void test_normal(void) {
    std::cout << "====> Standard example:" << std::endl;
    Foo f;
}

void test_thread(void) {
    std::cout << "====> Thread example:" << std::endl;
    Foo f;
    std::thread t(f);
    t.detach();
}


int main(int argc, char **argv) 
{
    test_normal();
    test_thread();

    for(;;);
}

Which prints the following: 其中打印以下内容:

在此输入图像描述

Why is the destructor called 6 times for the thread? 为什么析构函数被调用了6次? And why does the thread report different memory locations? 为什么线程会报告不同的内存位置?

EDIT When adding move and copy constructor output: 编辑添加移动和复制构造函数输出时:

在此输入图像描述

The function object will be moved or copied. 将移动或复制功能对象。 You didn't account in your output for any of these. 您没有在输出中考虑任何这些。

Add a copy constructor and move constructor to your class. 添加复制构造函数并将构造函数移动到您的类。

Foo(Foo const&) { std::cout << "Copy Constructor called: " << this << std::endl; }
Foo(Foo&&) { std::cout << "Move Constructor called: " << this << std::endl; }

Now if you run the code the output (on gcc 4.7.2) looks like this: 现在如果你运行代码 ,输出(在gcc 4.7.2上)看起来像这样:

====> Standard example:
Constructor called: 0xbff696ff
Destructor called: 0xbff696ff
====> Thread example:
Constructor called: 0xbff696ff
Copy Constructor called: 0xbff696cf
Move Constructor called: 0x93a8dfc
Destructor called: 0xbff696cf
Destructor called: 0xbff696ff
Operator called: 0x93a8dfc
Destructor called: 0x93a8dfc

As you can see, the number of calls to the destructor matches the number of calls to the various constructors. 如您所见,对析构函数的调用次数与对各种构造函数的调用次数相匹配。

I suspect gcc manages to elide a few of the copy / move construction calls that MSVC seems to be making, so there are fewer calls to destructor than your example. 我怀疑gcc设法忽略了MSVC似乎正在进行的一些复制/移动构造调用,因此对析构函数的调用比你的例子少。


Furthermore, you can avoid the copy construction completely by std::move ing the Foo object to the thread constructor. 此外,您可以通过std::move Foo对象std::move到线程构造函数来完全避免复制构造。

In test_thread change the thread construction line to test_thread中将线程构造线更改为

std::thread t(std::move(f));

Now the output looks like this: 现在输出如下:

====> Standard example:
Constructor called: 0xbfc23e2f
Destructor called: 0xbfc23e2f
====> Thread example:
Constructor called: 0xbfc23e2f
Move Constructor called: 0xbfc23dff
Move Constructor called: 0x9185dfc
Destructor called: 0xbfc23dff
Destructor called: 0xbfc23e2f
Operator called: 0x9185dfc
Destructor called: 0x9185dfc

Because your Foo is on the stack, not heap. 因为你的Foo在堆栈上,而不是堆。 This means that you allocate a new one inside test_thread, then it gets copied when you call std::thread(f) and again inside thread(f). 这意味着你在test_thread中分配一个新的,然后当你调用std :: thread(f)并再次调用thread(f)时它会被复制。

You would need to instead create a pointer to allocate on the heap, and pass that so that the object isn't copied each time, using the heap (new) to allocate it. 您需要创建一个指向堆上的分配的指针,然后传递它,以便每次都不会复制该对象,使用堆(新)来分配它。

Compiler adds default move and copy constructors if you do not do it yourself, check this 编译器添加默认的移动和复制构造函数,如果你自己不这样做,请检查这一点

https://ideone.com/wvctrl https://ideone.com/wvctrl

#include <iostream>
#include <thread>

class Foo {
public:
    Foo(Foo&& f) {
        std::cout << "Constructor Foo&& called: " << this << std::endl;
    }
    Foo(const Foo& f) {
        std::cout << "Constructor const Foo& called: " << this << std::endl;
    }
    Foo(void) {
        std::cout << "Constructor called: " << this << std::endl;
    }
    ~Foo(void) {
        std::cout << "Destructor called: " << this << std::endl;
    }
    void operator()() const {
        std::cout << "Operatior called: " << this << std::endl;
    }
};

void test_normal(void) {
    std::cout << "====> Standard example:" << std::endl;
    Foo f;
}

void test_thread(void) {
    std::cout << "====> Thread example:" << std::endl;
    Foo f;
    std::thread t(f);
    t.detach();
}


int main(int argc, char **argv) 
{
    test_normal();
    test_thread();

    for(;;);
}

it shows that all ctors pair with dtors. 它表明所有的ctors都与dtors配对。

Also look into this SO: 另外看看这个SO:

Rule-of-Three becomes Rule-of-Five with C++11? 三阶规则与C ++ 11一起成为五次规则?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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