HAO LEE
HAO LEE

Reputation: 193

Object destructor kept being called when multithreading, yet the object is not out of scope

I am not sure why even I called the object's member function, even it is still in it's scope, the destructor is still called. A simple example is shown as below:

#include<thread>
#include<iostream>
class Obj1
{
private:

public:
    ~Obj1();
    void testFunc();
};

Obj1::~Obj1()
{
    std::cout<<"destory\n";
}
void Obj1::testFunc(){
    std::cout<<"testfun\n";
}
#include "Obj1.hpp"
#include <thread>
#include <chrono>
int main()
{
    using namespace std::chrono_literals;
    Obj1 obj1 = Obj1();
    for(int i=0;i<100;i++){
        std::thread th =  std::thread(&Obj1::testFunc,obj1);
        std::this_thread::sleep_for(1s);
        std::cout<<"we wait\n";
    }
}

When I tried to run it, I can see the output:

destory
testfun
destory
we wait
terminate called without an active exception
Aborted (core dumped)

I wonder why obj1 is destroyed every time the thread ends? p.s. the reason for that 1s delay is because this is used in a realtime system, the main loop has a lower frequency, the task will be done before the next loop.

Upvotes: 0

Views: 87

Answers (1)

WhozCraig
WhozCraig

Reputation: 66254

The two biggest problems in your code:

  • You're making copies for each std::thread you launch.
  • You're not waiting for your threads to terminate.

A std::thread requires a callable, and if required, appropriate arguments. In your case the callable is pointer-to-member-function, which requires an object instance or address (std::thread will use either). You're giving it the former by way of making copies of obj1. If the intent is for all threads to access the same object, you should pass the address instead.

And then wait for the threads to terminate, of course

Code (with added messaging to detect copy-construction)

#include <iostream>
#include <vector>
#include <thread>

class Obj1
{
public:
    Obj1() { std::cout << "construct\n"; }
    Obj1(const Obj1&) { std::cout << "copy\n"; }
    ~Obj1() { std::cout << "destroy\n"; }

    void testFunc();
};

void Obj1::testFunc() {
    std::cout << "testfun\n";
}

int main()
{
    Obj1 obj1;

    std::vector<std::thread> threads;
    for (int i = 0; i < 10; ++i)
        threads.emplace_back(&Obj1::testFunc, &obj1); // <<== HERE

    for (auto& t : threads)
        t.join();
}

Output (can vary)

construct
testfun
testfun
testfun
testfun
testfun
testfun
testfun
testfun
testfun
testfun
destroy

Upvotes: 3

Related Questions