Search code examples
c++multithreadingc++11stdthread

std::thread, class constructor and destructor


When testing threads in C++11 I have created the following example:

#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:

enter image description here

Why is the destructor called 6 times for the thread? And why does the thread report different memory locations?

EDIT When adding move and copy constructor output:

enter image description here


Solution

  • 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:

    ====> 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.


    Furthermore, you can avoid the copy construction completely by std::moveing the Foo object to the thread constructor.

    In test_thread change the thread construction line to

    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