在范围结束前调用的析构函数

时间:2015-11-29 09:11:36

标签: c++ multithreading c++11

以下程序崩溃。但我真的不明白为什么。布尔my_shared_resouce在现实生活中是一个异步队列,最终通过消息传递停止线程内部的循环。 但是,以下程序崩溃,因为析构函数似乎被多次调用。第一次它在main()的睡眠结束前很久就完成了。如果我删除delete my_shared_resource;我可以看到析构函数被调用三次... 但是,根据我目前的理解,只有在main()完成时才会调用析构函数。

#include <thread>
#include <chrono>
#include <iostream>

using namespace std;

class ThreadedClass {

    public:

        ThreadedClass() {
            my_shared_resource = new bool(true);
        }

        virtual ~ThreadedClass() {
            delete my_shared_resource;
            cout << "destructor" << endl;
        }


        void operator()(){
            loop();
        }

        void stop() {
            *my_shared_resource = false;
        }

    private:

        void loop() {
            while (*my_shared_resource) {
                // do some work
                this_thread::sleep_for(std::chrono::milliseconds(1000));
            }
        }

        bool* my_shared_resource;
};

int main(int argc, char** argv) {

    ThreadedClass instance;
    std::thread t(instance);
    this_thread::sleep_for(std::chrono::milliseconds(1000));
    cout << "Did some work in main thread." << endl;
    instance.stop();
    t.join();
    return 0;
}

用g ++编译(Ubuntu 4.8.4-2ubuntu1~14.04)4.8.4

编译为g ++ --std = c ++ 0x thread.cpp -pthread

有人请告诉我这个设计有什么问题。

2 个答案:

答案 0 :(得分:3)

复制ThreadedClass后,两个副本都指向同一个my_shared_resource,并且两者都会将其删除。

改为使用std::shared_ptr<bool>

class ThreadedClass {
public:
    ThreadedClass() : shared_resource(new bool(true)) { } 
    virtual ~ThreadedClass() { }
    void operator()() { loop(); }
    void stop() { *shared_resource = false; }

private:
    void loop() {
        while (*shared_resource) {
            // Do some work.
            this_thread::sleep_for(std::chrono::milliseconds(1000));
        }
    }

    std::shared_ptr<bool> shared_resource;
};

答案 1 :(得分:2)

根据http://en.cppreference.com/w/cpp/thread/thread/thread 你在打电话:

template< class Function, class... Args > 
explicit thread( Function&& f, Args&&... args );

其中

创建新的std :: thread对象并将其与执行线程相关联。首先,构造函数将所有参数(包括函数对象f和所有args ...)复制/移动到线程可访问的存储

因此,您的my_shared_resourse指针会在线程对象的多个副本之间被复制和共享,并在多个位置被销毁。定义适当的复制构造函数/赋值运算符或使用共享指针。