You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++编译报错:use of deleted function ‘pQueue::pQueue(const pQueue&)’ 原因解析及解决方法求助

搞懂这个拷贝构造函数错误,一步步解决你的问题

嘿,作为C++新手碰到这个错误很正常,我来给你掰扯清楚到底咋回事,以及怎么解决。

首先先翻译一下你看到的错误:

error: use of deleted function ‘pQueue::pQueue(const pQueue&)’
note: is implicitly deleted because the default definition would be ill-formed

人话版本就是:你代码里某个地方在尝试复制一个pQueue对象,但C++本来应该自动帮你生成的“拷贝构造函数”被禁用了,用不了。为啥会被禁用?因为你的pQueue类里大概率藏着不能被复制的东西——比如std::thread(线程对象是不能复制的,总不能把一个正在跑的线程复制成另一个吧),C++发现这种情况,就直接把默认的拷贝构造函数给“删了”,不让你用。

接下来看看你代码里的几个核心问题,正是这些问题导致了错误,同时也让你的队列类根本没起到作用:

问题1:你的队列是个“一次性”局部变量,不是类的成员

你看pQueue的构造函数:

pQueue::pQueue() {
    std::priority_queue<std::pair<int, Category*>> q;
}

这里的q只是构造函数里的临时变量,构造函数跑完就没了!你的queueWork和doWork函数用的都是自己参数里的队列,完全和这个临时变量没关系——相当于你写了个队列类,但类里根本没存队列,这哪行啊?

问题2:函数参数传值方式完全错了

你的queueWork和doWork都把std::priority_queue作为传值参数:

void queueWork(std::priority_queue<std::pair<int, Category*>> q, int action, Category* data)

传值意味着每次调用函数都会复制整个队列,不仅效率低,而且你改的是复制后的临时队列,原队列根本不会变!更糟的是,如果队列关联了不能复制的东西(比如线程),就会触发你看到的错误。

问题3:非静态成员函数调用错了

在main.cpp里你写了:

pQueue::queueWork(Queue, action, data);

queueWork是pQueue的非静态成员函数,必须通过pQueue的对象来调用,比如Queue.queueWork(action, data);,你把对象当参数传进去,不仅类型不匹配,还会触发对象拷贝,直接撞到那个“拷贝构造函数被删除”的错误上。

现在给你一步步改代码,解决所有问题

第一步:修复pQueue类的结构

先在file.h里给pQueue加上真正的成员变量——队列、线程、互斥锁(多线程操作队列必须加锁,不然会乱套):

#pragma once
#include <queue>
#include <thread>
#include <mutex>

// 前置声明Category,避免头文件依赖
class Category;

class pQueue {
public:
    pQueue();
    ~pQueue();
    // 删掉多余的队列参数,直接操作类里的成员队列
    void queueWork(int action, Category* data);
private:
    // 同样删掉队列参数
    void doWork();
    // 类的核心:成员队列
    std::priority_queue<std::pair<int, Category*>> queue_;
    // 执行doWork的工作线程
    std::thread worker_thread_;
    // 保护队列的互斥锁,防止多线程抢着改队列
    std::mutex queue_mutex_;
    // 用来停止线程的标志
    bool stop_flag_ = false;
};

第二步:实现构造和析构函数

在file.cpp里,构造函数启动工作线程,析构函数安全停止线程:

#include "File.h"
#include <utility>

pQueue::pQueue() : stop_flag_(false) {
    // 启动线程,让线程执行当前对象的doWork函数
    worker_thread_ = std::thread(&pQueue::doWork, this);
}

pQueue::~pQueue() {
    // 设置停止标志,告诉线程可以退出了
    stop_flag_ = true;
    // 等待线程执行完再销毁对象
    if (worker_thread_.joinable()) {
        worker_thread_.join();
    }
}

第三步:修复queueWork和doWork函数

现在这两个函数直接操作类里的成员队列,并且用互斥锁保护:

void pQueue::queueWork(int action, Category* data) {
    // 加锁,确保同一时间只有一个线程在改队列
    std::lock_guard<std::mutex> lock(queue_mutex_);
    // 把任务加入队列
    queue_.emplace(action, data);
}

void pQueue::doWork() {
    // 线程循环,直到收到停止信号
    while (!stop_flag_) {
        std::pair<int, Category*> task;
        {
            // 加锁访问队列
            std::lock_guard<std::mutex> lock(queue_mutex_);
            // 如果队列为空,就跳过这次循环,避免空转
            if (queue_.empty()) {
                continue;
            }
            // 取出队列顶部的任务
            task = queue_.top();
            queue_.pop();
        } // 锁在这里会自动释放,不用手动解锁

        // 这里处理你的任务
        Category* data = task.second;
        // 比如调用你的处理逻辑:bool result = function(data);
        // TODO: 处理任务结果,比如存到线程安全的容器里
    }
}

第四步:修复main.cpp里的调用

现在用正确的方式调用成员函数:

#include "File.h"

bool function(Category* data) {
    if (data) {
        int action = 1;
        // 创建一个pQueue对象
        pQueue my_queue;
        // 通过对象调用queueWork,传入任务参数
        my_queue.queueWork(action, data);
        // TODO: 实现获取任务结果的逻辑
    }
    return true;
}

再回头说那个拷贝构造函数错误

现在你知道了:因为pQueue里有std::thread成员,线程是不能复制的,所以C++自动删除了默认的拷贝构造函数。之前你错误地把pQueue对象当参数传,相当于要复制这个对象,自然就触发了错误。现在我们的代码里不会再尝试复制pQueue对象,这个错误也就消失了。

额外提醒

  • 多线程操作队列一定要用互斥锁,不然会出现“竞态条件”,程序可能崩溃或者数据乱掉。
  • 如果想优化线程空转的问题,可以用std::condition_variable,让线程在队列为空时休眠,有新任务再唤醒,这样更省CPU。
  • 注意Category*的内存管理,用完要记得释放,避免内存泄漏。

内容的提问来源于stack exchange,提问作者Friday

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.28 18:37:31