std::make_pair与std::atomic_bool的GCC版本编译差异原因
GCC 4.9.0与GCC 12.1编译std::map<int, std::atomic>插入逻辑差异的底层原因
问题复现代码
#include <map> #include <atomic> #include <utility> class Test { public: Test() { mp_.insert(std::make_pair(1, true)); } private: std::map<int, std::atomic<bool>> mp_; };
上述代码在GCC 4.9.0下开启C11及以上编译选项时,会报无匹配insert函数、无法将std::pair<int, bool>转换为std::pair<const int, std::atomic<bool>>的错误,GCC 12.1下相同选项可正常编译,核心原因来自std::atomic的语义特性、旧版本libstdc的实现缺陷、C++标准演进三个层面:
std::atomic的拷贝语义限制
从C++11标准开始,std::atomic<T>的拷贝构造、拷贝赋值运算符就被显式标记为删除,仅支持移动语义,以及从底层类型T的直接隐式构造。std::make_pair(1, true)生成的临时对象类型是std::pair<int, bool>,和map的value_type即std::pair<const int, std::atomic<bool>>并不匹配,插入时需要完成类型转换。- GCC 4.9.0的libstdc实现缺陷
GCC 4.9.0发布于2014年,对C11标准的实现尚未完善。其配套libstdc++中map::insert的泛型重载(用于支持传入可转换为value_type的参数)的类型约束存在漏洞:仅支持入参能整体直接转换为value_type的场景,无法识别pair类型的逐元素构造转换路径。编译器不会自动推导std::pair<int, bool>可以通过逐字段构造(int转const int、bool转std::atomic)生成目标value_type,因此匹配不到对应的insert重载,最终抛出类型转换错误。 - 高版本GCC兼容的原因
后续版本的libstdc逐步修复了这一实现缺陷,完善了泛型insert重载的类型判断逻辑,能够正确识别pair类型的逐元素转换合法性;C17标准正式落地后,也明确要求pair支持从元素类型可转换的其他pair做隐式构造。到GCC 12.1版本时,这部分逻辑已经完全符合标准要求:编译器可以识别传入的std::pair<int, bool>能够逐字段原位构造map的value_type,构造过程中std::atomic<bool>直接从bool参数生成,不需要调用被删除的拷贝构造函数,因此可以正常编译。
旧版本兼容方案
如果需要兼容GCC 4.9.0这类老版本编译器,可以绕过类型转换逻辑,直接构造匹配类型的对象或使用原位插入接口:
// 方案1:直接构造map value_type类型的对象传入 mp_.insert(std::pair<const int, std::atomic<bool>>(1, true)); // 方案2:调用emplace接口直接在容器内构造元素,不需要中间类型转换 mp_.emplace(1, true);
内容的提问来源于stack exchange,提问作者John
相关产品推荐
相关产品推荐

