为何该C++程序在macOS可编译但Ubuntu不行?Clang版本均为10
这不是未定义行为,本质是两个系统使用了不同的C标准库实现带来的差异:Ubuntu上的Clang搭配的是GCC的**libstdc,而macOS上的Clang用的是LLVM的libc++**,两者对std::atomic<T>的实现细节有区别。
为什么Ubuntu编译失败?
根据C14标准,std::atomic<T>只要求T是**可平凡复制(trivially copyable)**的类型,但你Ubuntu上用的旧版本libstdc(搭配的是GCC 5.4.0)在实现atomic::load()时,会尝试默认构造一个T类型的临时对象(错误信息里的_Tp tmp;就是这个操作),这就要求T必须有可访问的默认构造函数。而你的foo类只定义了带两个参数的构造函数,编译器不会自动生成默认构造函数,所以触发了编译错误。
反观macOS的libc++,它的atomic::load()实现没有依赖默认构造函数,而是直接通过内存操作读取值,不需要临时对象的默认构造,所以你的代码能正常编译。
如何让两个环境编译结果一致?
有几种可行的方案:
给
foo添加默认构造函数:这是最直接且兼容性最好的方法,比如:struct foo { bool bar; int baz; foo() = default; // 显式声明默认构造函数 foo(bool bar, int baz) : bar(bar), baz(baz) { } };这样既满足libstdc的要求,也不会影响libc的编译。
升级Ubuntu上的libstdc++版本:较新的libstdc++已经修正了这个问题,不再要求
T必须有默认构造函数(只要满足可平凡复制即可)。如果你的Ubuntu系统允许,可以升级到更高版本的GCC标准库。在Ubuntu上强制使用libc++编译:如果你想和macOS保持一致的标准库,可以让Clang使用libc++编译,命令如下:
clang++ -std=c++14 -stdlib=libc++ test.cpp -o test注意:Ubuntu默认可能没有安装libc++,需要先执行
sudo apt install libc++-dev libc++abi-dev完成安装。
补充说明
你提到从std::atomic的文档里找不到默认构造函数的要求,这完全正确——C标准确实没有这个要求,这只是旧版libstdc的实现细节。macOS的libc++实现更贴合标准的规定,所以没有这个额外限制。
内容的提问来源于stack exchange,提问作者oarfish

