2017-06-13 45 views
2

这是我的问题。试图引用已删除的函数,具有互斥成员的结构

我有这样的结构。

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

当建立我的代码,我得到这个错误

错误C2280 threadInfo::threadInfo(const threadInfo &):尝试 引用删除的功能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); 

我猜结构正在某处存在复制的代码,但我完全缺少的地方。

+0

请发布[MCVE] – Rama

+2

不要复制结构? ('condition_variable'和'mutex'都将它们的拷贝标记为删除) – Borgleader

+0

添加了正在使用结构的代码示例。 – lhbortho

回答

1

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

#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; 
} 
+0

你可以使用'emplace'和'std :: move'。 'threadInfo'将有一个由编译器定义的隐式移动构造函数。你可以做'threadList.emplace(it,std :: move(info));'并且不需要专门的构造函数。 –

+0

是的,工作。最简单的答案,也很容易纳入其他类似的问题。感谢您展示存在! – lhbortho

+0

@FrançoisAndrieux我想这只是个人喜好,在这一点上?任何理由都会比另一个更好? – lhbortho

0

在标准C++库中,与线程相关的类(如互斥体)没有复制构造函数。

当一个任务涉及两个物体,如

Class b(10); 
Class a = b; 

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

由于有两个相同的互斥体副本不好,所以该库不会将这种方法用于与线程相关的类。

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

要解决,您将不得不显式定义一个复制构造函数并手动处理。请注意,您应该记住与线程(如互斥体和cv)相关的内容不应存在于多个副本中。

+0

第二行复制int ... – Borgleader

+0

这是'threadList.insert'和'threadList.push_back'调用,它试图复制'threadInfo'实例。 – IInspectable

+0

这个答案似乎不完整。还有一种解决方法是不使用'std :: move'替代'push_back'和'insert'使用'emplace'类型函数进行复制。 –

0

显式删除互斥体的复制构造函数。但是,如果您正在做的是移动而不是复制(例如,您不需要您的threadInfo对象的旧值),则无法复制互斥锁,而只能使用std::move移动互斥锁并为您编写移动构造函数threadInfo对象。

但是,移动构造函数可能会导致难以发现错误,所以我不会推荐这样做。更直接的方法是将你的“信息”对象包装在指针中并使用它。你可以做到这一点这样:

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,这是“最简单”的方式做到这一点,因为它不会破坏任何东西,但可能不希望你想要做的,你最想做的事情是给你的info对象的'threadList'对象所有权。在这种情况下,您将声明它为unique_ptr:

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

and move it into the threadList: 

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