尝试引用已删除的函数,使用互斥锁成员进行结构

时间:2017-06-13 18:20:12

标签: c++ data-structures mutex

这是我的问题。

我有这样的结构。

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);

我猜结构正在那里的某处被复制,但我完全错过了哪里。

3 个答案:

答案 0 :(得分: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;
}

答案 1 :(得分:0)

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

当作业涉及两个对象时,例如

package bash

import com.github.kittinunf.fuel.httpGet
import com.github.kittinunf.result.Result

fun main(args: Array<String>) {
    val bashImHost = "http://bash.im/"
    bashImHost.httpGet().responseString { request, response, result ->
        when (result) {
            is Result.Failure -> {
                println("Some kind of error!")
            }
            is Result.Success -> {
                val htmlBody = result.value
                val parsePattern = "<div class=\"text\">(.+)</div>"
                val parseRegex = Regex(parsePattern)
                val results = parseRegex.findAll(htmlBody)
                results.iterator().forEach { resultItem -> println(resultItem.groups[1]?.value) }
            }
        }
    }
}

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

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

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

要解决此问题,您必须明确定义复制构造函数并手动处理。请注意,您应该记住,与mutex和cv等线程相关的内容不应存在于多个副本中。

答案 2 :(得分:0)

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

然而,移动构造函数可能导致很难发现bug,所以我不建议这样做。更直接的方法是将“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,这是“最简单”的方法,因为它不会破坏任何东西,但可能不想让你想做,你最想要的是什么do,给出infoList对象的'threadList'对象。在这种情况下,您将其声明为unique_ptr:

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

and move it into the threadList:

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