【问题标题】:Destructor called before end of scope在作用域结束之前调用析构函数
【发布时间】:2016-03-03 01:24:23
【问题描述】:

以下程序崩溃。但我真的不明白为什么。布尔值 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

谁能告诉我这个设计有什么问题。

【问题讨论】:

  • 你有一个数据竞赛,顺便说一句。使用std::atomic&lt;bool&gt;

标签: c++ multithreading c++11


【解决方案1】:

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

改用std::shared_ptr&lt;bool&gt;

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;
};

【讨论】:

  • 哦,它被复制了,doooo.. 这完全解释了它。而且我相信我可以给 shared_pointer 一个自定义的免费功能,因为在我更大的程序中,我显然犯了同样的错误。但是有一个 GAsycQueue* 被 g_async_queue_unref() 销毁,这些是 C 结构和函数
  • @hetepeperfan 是的,你可以给shared_ptr一个自定义删除函数。
【解决方案2】:

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

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

哪个

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-05-02
    • 2020-11-16
    • 2018-12-06
    • 2014-11-27
    • 1970-01-01
    • 2016-01-03
    • 1970-01-01
    相关资源
    最近更新 更多