尝试使用 std::thread 和 std::vector 引用已删除的构造函数?

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

我正在尝试使用一个 C++ 类(带有构造函数和析构函数),该类在

std::thread
对象中具有
std::vector
字段。我使用 C++ 17 和 Visual Studio 2022 编译下面所示的所有示例。


这是一个简单的最小示例,说明了我的问题:

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

class TEST
{
public:
    std::thread t;
    bool done;

    TEST()
    {
        this->done = false;
        this->t = std::thread(&TEST::foo, this);
    }

    ~TEST()
    {
        this->done = true;
        this->t.join();
    }

    void foo()
    {
        std::cout << "foo\n";
        while (!this->done) {};
    }
};

int main()
{
    std::vector<TEST> vec = {};
    vec.push_back(TEST());
    vec.clear();

    return 0;
}

我在

vec
函数中创建一个向量
main
,其中包含
TEST
类的对象,添加一个
TEST
对象,然后立即清除该向量。
TEST
类包含一个名为
std::thread
t
字段、一个名为
bool
done
字段以及默认的构造函数和析构函数。字段
t
中创建的每个线程仅调用
foo
函数,将
foo
打印到控制台,并等待直到析构函数将
done
字段设置为
true
,然后退出。析构函数只是加入线程。

上面例子编译时提示的具体错误如下:

Error   C2280   'TEST::TEST(const TEST &)': attempting to reference a deleted function  

据我了解,出现此错误的核心原因是

std::thread
类故意是不可复制的,因此它的复制构造函数在标准库中被显式删除。因此,当编译器尝试查找我的
TEST
类的默认复制构造函数时,它无法找到
std::thread
的复制构造函数,并且编译失败。

但是,我很难理解的是,只有当我添加默认析构函数

~TEST
时,才会出现此错误。删除它允许代码编译,尽管程序在运行时崩溃,我假设是因为
t
线程字段在对象销毁时没有正确退出。我不明白为什么这个错误只在我显式添加析构函数时才会出现,而不会在隐式空默认构造函数中出现。


我注意到的另一件事是,这段代码似乎可以在不使用

std::vector
的情况下编译和运行,没有问题,例如以下示例:

#include <iostream>
#include <thread>

class TEST
{
public:
    std::thread t;
    bool done;

    TEST()
    {
        this->done = false;
        this->t = std::thread(&TEST::foo, this);
    }

    ~TEST()
    {
        this->done = true;
        this->t.join();
    }

    void foo()
    {
        std::cout << "foo\n";
        while (!this->done) {};
    }
};

int main()
{
    {
        TEST test = TEST();
    }

    return 0;
}

我只是在

TEST
函数中创建一个独立的
main
对象,没有
std::vector
,并立即销毁它,编译和执行没有问题。看起来
TEST
中存在
std::vector
对象只会导致
~TEST
析构函数无法编译。

我还尝试使用 emplace_back

std::vector
 函数代替 
push_back
,如 另一个帖子 所建议,出现相同的错误。


这是怎么回事?为什么

std::thread
中存在带有
std::vector
字段的对象会导致编译失败,而此类独立对象则不会?

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

当您声明类编译器的析构函数时,不会生成移动和复制构造函数。为了让

std::vector::emplace_back
发挥作用,你的班级至少必须是可移动的。要修复它,只需将这些声明添加到您的类中即可:

TEST(TEST&& other) = default;
TEST& operator=(TEST&& other) = default;
© www.soinside.com 2019 - 2024. All rights reserved.