vector 在 std::thread 执行 operator() 时变为空

问题描述 投票:0回答:1

我正在尝试创建一个线程 (PrinStringManager),该线程又会创建多个线程 (PrintEntry)(取决于传入的字符串向量的元素数量)。 创建的每个 PrintEntry 线程只打印构造函数中接收到的字符串。

这只是代表我的问题的一个小例子。

class PrintEntry
{
public:
    PrintEntry(std::string& name) :name_(name) {}
    ~PrintEntry() {}
    void operator()() {
        std::cout << "name: " << name_;
    }
private:

    std::string name_;
};

class PrinStringManager
{
public:
    PrinStringManager(std::vector<std::string>& vec) :vec_(vec){}
    ~PrinStringManager() {
        for (auto& t : vt_) t.join();
    }

    void operator()() {
        for (auto name : vec_)
        {
            vt_.emplace_back(PrintEntry{ name });
        }
    }

private:

    std::vector<std::string> vec_;
    std::vector<std::thread> vt_;
};


void f()
{
    std::vector<std::string> vec{ "one","two", "three" };
    PrinStringManager psm{ vec };
    std::thread t{ std::ref(psm) };
    t.detach();
} 

int main()
{
    f();
    while (true)
    {
        std::this_thread::sleep_for(std::chrono::milliseconds(1000));
    }
    std::cout << "Hello World!\n";
}

发生的事情是,对象 PrinStringManager 是用 3 个字符串的向量创建的,但是当线程调用对象函数(来自 PrintStringmanager)时,向量为空:

void operator()() {
    for (auto name : vec_) //<-- vec is empty!!
    {
        vt_.emplace_back(PrintEntry{ name });
    }
}

我注意到,当函数 f() 的范围结束时,将调用 PrinStringManager 的析构函数,这应该是问题所在。

有没有办法在不将 PrinStringManager 设置为静态的情况下以简单的方式解决这个问题,使其永远存在?

有没有办法在线程对象内部移动 psm,以便在达到 f() 范围的末尾时,线程内部的 psm 保持原始值?

c++ stdvector stdthread
1个回答
0
投票

首先通过添加移动构造函数使您的对象可移动:

    // No implicitly declared one since you have a destructor, so bring it back
    PrinStringManager(PrinStringManager&&) = default;
    // Also the move assign is probably wanted
    PrinStringManager& operator=(PrinStringManager&&) = default;

// (And also fix `PrintEntry`, probably by removing the destructor)

然后你可以让线程持有它自己的

PrinStringManager
对象,而不仅仅是对堆栈中一个对象的引用:

// The thread will hold a PrinStringManager move-constructed from psm
std::thread t{ std::move(psm) };

如果你因为任何原因不能使

PrinStringManager
可移动,你可以使用动态分配:

void f()
{
    std::vector<std::string> vec{ "one","two", "three" };
    auto psm = std::make_unique<PrinStringManager>(vec);
    // The thread holds a pointer to `psm` which is deleted
    // when the thread finishes
    std::thread t{ [psm=std::move(psm)]{ (*psm)(); } };
    t.detach();
}
© www.soinside.com 2019 - 2024. All rights reserved.