试图引用已删除的函数、具有互斥成员的结构

Attempting to reference a deleted function, structure with mutex member

这是我的问题。

我有这样的结构。

struct threadInfo
{
    std::condition_variable cv;
    std::mutex m;
    int priorityLevel;
};

构建代码时出现此错误

Error C2280 threadInfo::threadInfo(const threadInfo &): attempting to reference a deleted function PriorityListMutex

根据我的理解,这意味着 threadInfo 的构造函数被调用并且它试图复制 mutex 这是不可能的。

我对 C++ 没有太多经验,虽然我有点了解正在发生的事情,但我不确定如何尝试解决这个问题。任何帮助都会很棒!

这里是使用ThreadInfo的代码

    threadInfo info;
    info.priorityLevel = priority;

    priorityListMutex.lock(); 
    for (std::list<threadInfo>::iterator it = threadList.begin(); it != threadList.end(); it++) 
    {
        if ((*it).priorityLevel < info.priorityLevel)
        {
            threadList.insert(it, info); 
            break; 
        }
        else if (it == threadList.end())
        {
            threadList.push_back(info);
            break;
        }
    }
    priorityListMutex.unlock();
    std::unique_lock<std::mutex> lock(info.m);
    info.cv.wait(lock);

我猜结构正在那里的某个地方被复制,但我完全不知道在哪里。

在标准 C++ 库中,class与线程相关的元素,如互斥量,没有复制构造函数。

当一个赋值涉及两个对象时,比如

Class b(10);
Class a = b;

在第二行,我们尝试创建一个从另一个对象初始化的对象。这使得编译器寻找一个复制构造函数,一个专门为此目的开发的构造函数。

由于具有两个相同的互斥锁副本并不好,库不会将这种方法用于与线程相关的 classes。

通常编译器会创建默认的复制构造函数以备不时之需,但是当 class 这种类型的 属性 时它不能这样做,所以它给你和错误。

要解决这个问题,您必须显式定义一个复制构造函数并手动处理。当心,你应该记住,与线程相关的东西,如 mutex 和 cv 不应该存在超过一个副本。

mutex的复制构造函数被显式删除。但是,如果您正在做的是移动而不是复制(例如,您不需要 threadInfo 对象的旧值),那么您不能复制互斥锁,那么您可以使用 std::move 移动互斥锁并编写一个为您的 threadInfo 对象移动构造函数。

但是,移动构造函数可能导致难以发现错误,因此我不推荐这样做。更直接的方法是将 "info" 对象包装在一个指针中并使用它。您可以这样实现:

auto info = std::make_shared<threadInfo>{};
info->priorityLevel = priority;

priorityListMutex.lock(); 
for (std::list<std::shared_ptr<threadInfo>>::iterator it = threadList.begin(); it != threadList.end(); it++) 
{
    if ((*it).priorityLevel < info->priorityLevel)
    {
        threadList.insert(it, info); 
        break; 
    }
    else if (it == threadList.end())
    {
        threadList.push_back(info);
        break;
    }
}
priorityListMutex.unlock();
std::unique_lock<std::mutex> lock(info.m);
info->cv.wait(lock);

但是请注意,在这种情况下,我使用的是 shared_ptr,这是 "easiest" 的方法,因为它不会破坏任何东西,但可能不希望你想要做,你最有可能想做的,是给你的信息对象的 'threadList' 对象所有权。在这种情况下,您可以将其声明为 unique_ptr:

auto info = std::make_uniq<threadInfo>{};

and move it into the threadList:

threadList.insert(it, std::move(info)); 

您可以通过避免复制并将结构直接放置在列表中来解决您的问题。不过,这确实需要自定义构造函数。我已将您的代码示例缩短为仅显示放置部分:

#include <mutex>
#include <condition_variable>
#include <list>

struct threadInfo
{
    explicit threadInfo(int prio) : priorityLevel(prio) {}

    std::condition_variable cv;
    std::mutex m;
    int priorityLevel;
};

int main()
{
    std::list<threadInfo> threadList;

    int priorityLevel = 0;

    for (std::list<threadInfo>::iterator it = threadList.begin(); it != threadList.end(); it++) 
    {
        if ((*it).priorityLevel < priorityLevel)
        {
            threadList.emplace(it, priorityLevel); 
            break; 
        }
        else if (it == threadList.end())
        {
            threadList.emplace_back(priorityLevel);
            break;
        }
    }

    return 0;
}