无法编译std::vector<safe_queue<std::pair>>的C++技术问题求助
排查你的MapReduce多线程队列编译错误
让我直接点出问题核心,再给你两种可行的解决办法:
错误根源
你的safe_queue类里包含了std::mutex和std::condition_variable这两个成员——它们是不可移动、不可拷贝的(标准库明确禁用了它们的拷贝/移动构造函数)。当一个类包含这类成员时,编译器会自动删除默认的拷贝构造、移动构造以及对应的赋值运算符。
而你在主函数里写的task_queues.push_back(safe_queue<...>()),是把一个临时的safe_queue对象塞到vector里。vector的push_back会尝试移动这个临时对象到容器内存中,但你的safe_queue没有可用的移动构造函数,所以编译器直接报错了。
解决办法
方案1:用emplace_back直接在vector里构造对象(推荐)
最简单的解决方式就是跳过临时对象的创建,直接在vector的内存空间里构造safe_queue,这样完全不需要移动或拷贝操作:
int main(int argc, char * argv[]) { std::vector<safe_queue<std::pair<std::string, int>>> task_queues; // 直接在vector内部构造safe_queue,无移动/拷贝开销 task_queues.emplace_back(); task_queues[0].push(std::make_pair("hello", 0)); // 用make_pair更简洁 }
方案2:手动实现移动构造函数(仅当必须移动对象时使用)
如果你确实需要移动safe_queue对象(比如从函数返回一个队列),可以手动实现移动构造函数。注意:我们不能移动mutex和condition_variable,只能重新初始化它们,同时安全地转移队列里的元素:
template <typename T> class safe_queue { private: std::mutex d_mutex; std::condition_variable d_condition; std::deque<T> d_queue; public: safe_queue() {} // 移动构造函数:锁定原对象,转移队列元素,初始化新的同步原语 safe_queue(safe_queue&& other) { std::unique_lock<std::mutex> lock(other.d_mutex); d_queue = std::move(other.d_queue); // mutex和condition_variable会默认初始化新的实例,原对象的同步原语不再被使用 } // 明确禁用拷贝构造和拷贝赋值(因为mutex无法拷贝) safe_queue(const safe_queue&) = delete; safe_queue& operator=(const safe_queue&) = delete; // 可选:禁用移动赋值,或者根据需求实现 safe_queue& operator=(safe_queue&&) = delete; void push(T value) { { std::unique_lock<std::mutex> lock(d_mutex); d_queue.push_front(std::move(value)); // 用move优化性能 } d_condition.notify_one(); } T pop() { std::unique_lock<std::mutex> lock(d_mutex); d_condition.wait(lock, [this]{ return !d_queue.empty(); }); // 用this捕获更清晰 T rc = std::move(d_queue.back()); d_queue.pop_back(); return rc; } };
实现后,你原来的push_back代码就能正常工作了,但这个方案需要小心处理线程安全,所以除非必要,优先用方案1。
额外小贴士
std::make_pair比直接构造std::pair更简洁,还能自动推导类型- 在
push和pop里用std::move可以避免不必要的拷贝,提升性能 - 永远不要试图拷贝或移动
std::mutex/std::condition_variable,这会导致未定义行为
内容的提问来源于stack exchange,提问作者Mario Leonardo Salinas
相关产品推荐
相关产品推荐

