使用emplace向std::map插入含mutex的struct时触发C2660错误求助
std::map emplace插入含锁的结构体失败问题分析与解决
问题代码
struct Queue_ctx { std::mutex qu_mutex; std::condition_variable qu_cv; std::queue<std::vector<std::byte>> qu; }; std::map<std::string, Queue_ctx> incoming_q_map; Queue_ctx qctx; std::vector<std::byte> vect(100); qctx.qu.push(vect); incoming_q_map.emplace("actor", qctx);
编译错误信息
error C2660: 'std::pair<const std::string,main::Queue_ctx>::pair': function does not take 2 arguments message : see declaration of 'std::pair<const std::string,main::Queue_ctx>::pair' message : see reference to function template instantiation 'void std::_Default_allocator_traits<_Alloc>::construct<_Ty,const char(&)[6],main::Queue_ctx&>(_Alloc &,_Objty *const ,const char (&)[6],main::Queue_ctx &)' being compiled with [ _Alloc=std::allocator<std::_Tree_node<std::pair<const std::string,main::Queue_ctx>,std::_Default_allocator_traits<std::allocator<std::pair<const std::string,main::Queue_ctx>>>::void_pointer>>, _Ty=std::pair<const std::string,main::Queue_ctx>, _Objty=std::pair<const std::string,main::Queue_ctx> ]
问题原因
- std::map的元素本质是pair:std::map的每个元素都是
std::pair<const std::string, Queue_ctx>类型,emplace的作用是在map的内存空间中原地构造这个pair,因此编译器会尝试将你传入的参数转发给pair的构造函数。 - Queue_ctx不可拷贝:
std::mutex和std::condition_variable是不可拷贝、不可移动的类型,编译器会自动删除Queue_ctx的拷贝构造函数和移动构造函数。当调用emplace("actor", qctx)时,需要用qctx拷贝构造pair的第二个成员,但拷贝构造函数已被删除,导致找不到匹配的pair构造函数,触发C2660错误。 - 默认构造函数没问题:
Queue_ctx的默认构造函数是存在的,会正确初始化mutex、condition_variable和queue,但这和拷贝构造被删除的问题无关。
修复方案
因为Queue_ctx无法拷贝或移动,只能在map内部原地构造,然后直接操作map中的实例:
方案一:先构造空实例,再添加数据
std::map<std::string, Queue_ctx> incoming_q_map; // 原地构造空的Queue_ctx实例 auto [iter, success] = incoming_q_map.emplace("actor", Queue_ctx{}); // C++17之前写法: // auto iter = incoming_q_map.emplace("actor", Queue_ctx{}).first; // 获取map中Queue_ctx的引用,向队列添加数据 std::vector<std::byte> vect(100); iter->second.qu.push(vect);
方案二:使用piecewise_construct原地构造(自定义初始化场景)
如果需要在构造时就初始化qu成员,可以用std::piecewise_construct分别构造pair的两个部分:
std::map<std::string, Queue_ctx> incoming_q_map; std::vector<std::byte> vect(100); incoming_q_map.emplace( std::piecewise_construct, std::forward_as_tuple("actor"), // 构造key部分 std::forward_as_tuple( std::mutex{}, // 初始化mutex std::condition_variable{}, // 初始化condition_variable std::queue<std::vector<std::byte>>{} // 初始化queue,也可传入可移动的已有队列 ) ); // 后续通过引用操作队列 auto& qctx = incoming_q_map["actor"]; qctx.qu.push(std::move(vect));
补充说明
- 尝试
make_pair无效,本质原因还是Queue_ctx不可拷贝,make_pair同样需要拷贝qctx,因此无法通过编译。 - 注释掉
qu_mutex和qu_cv后,Queue_ctx只剩可拷贝的std::queue,编译器会生成默认拷贝构造函数,因此emplace可以正常工作。
内容的提问来源于stack exchange,提问作者irsis
相关产品推荐
相关产品推荐

