在vector成员变量中存储thread触发断点

Storing thread in vector member variable triggers breakpoint

我有一个名为 Executor 的 class,它有一个 vector 作为成员变量。 submit(const std::function& f) 成员函数应该将传递的 lambda 作为线程启动并将其添加到向量中。析构函数连接存储在向量中的所有线程。 第一个 lambda 打印结果,但之后我的代码不知何故遇到了断点。 我做错了什么?

这是我的 Executor.h 代码:

#include <thread>
#include <mutex>
#include <iostream>
#include <vector>
#include <functional>

using namespace std;
class Executor
{
protected:
    vector<thread*> threads;
    mutex m;
public:
    void submit(const std::function<void()>& f);
    Executor();
    ~Executor();
};

Executor.cpp:

#include "Executor.h"

void Executor::submit(const std::function<void()>& f)
{
    
    {
        lock_guard<mutex> lock(m);
        thread t(f);
        
        threads.push_back(&t);
    }
    
}

Executor::Executor() {}

Executor::~Executor()
{
    for (unsigned int i = 0; i < threads.size(); i++)
    {
        threads.at(i)->join();
        delete threads.at(i);
    }
    threads.clear();
}

和 main():

Executor ex;
        auto fact = [](){cout<< "factor(55) = " << factor(55); };
        auto pk = [](){cout << "P2(100, 50) = " << P2(100, 50); };
        auto fib = [](){cout << "fibonacci(45) = " << fibonacci(45); };


        ex.submit(fact);
        ex.submit(pk);
        ex.submit(fib);

threads.push_back(&t); 中,指针 &t 仅在声明 t 的范围结束之前有效。这会导致 3 个问题:

  1. submit 内范围的末尾,线程在未调用 join 的情况下被破坏,导致 std::terminate 被调用
  2. Executor 的析构函数中 ->join 在悬空指针上调用
  3. Executor 的析构函数中,您调用了 delete 未分配给 new
  4. 的内容

在这段代码中不需要使用指针,如果你将线程直接存储在向量中你的代码会更简单和更安全:

class Executor
{
protected:
    vector<thread> threads;
    mutex m;
public:
    void submit(const std::function<void()>& f);
    Executor();
    ~Executor();

    Executor(const Executor&) = delete;
    Executor& operator=(const Executor&) = delete;
};

void Executor::submit(const std::function<void()>& f)
{  
    {
        lock_guard<mutex> lock(m);
        threads.emplace_back(f);
    }   
}

Executor::Executor() {}

Executor::~Executor()
{
    for (auto& thread : threads)
    {
        thread.join();
    }
    threads.clear();
}

注意我还删除了复制构造函数和赋值运算符以符合 rule of three