boost::atomic要求类型可平凡复制,为何非平凡类型代码仍能运行?
为何boost::atomic能正常运行,尽管atom并非可平凡复制类型?
boost::atomic的文档明确要求模板参数T必须是**可平凡复制(trivially copyable)**类型,但以下代码中,atom结构体包含std::string(非平凡复制类型),却能正常编译运行,这是为什么?
#include <chrono> #include <iostream> #include <memory> #include <unordered_set> #include <parallel/algorithm> #include <boost/algorithm/cxx11/all_of.hpp> #include <boost/atomic.hpp> #include <boost/optional/optional.hpp> #include <boost/range/algorithm/copy.hpp> #include <boost/range/algorithm/count_if.hpp> #include <boost/range/algorithm/remove_if.hpp> #include <boost/range/algorithm/sort.hpp> #include <boost/range/algorithm/unique.hpp> #include <boost/range/irange.hpp> #include <boost/range/numeric.hpp> typedef uint32_t vint; // Integer for vertex IDs constexpr vint vmax = std::numeric_limits<vint>::max(); // Used as invalid ID struct atom { boost::atomic<float> str; // Total weighted degree of the community members boost::atomic<vint> child; // Last vertex that is merged to this vertex std::string c; }; struct vertex { boost::atomic<atom> a; boost::atomic<vint> sibling; vint united_child; }; int main() { std::cout << "Is 'atom' trivially copyable? " << std::boolalpha << std::is_trivially_copyable<atom>::value << std::endl; return 0; }
原因解析
- Boost.Atomic的约束是文档规范,而非编译期强制检查:Boost.Atomic对T的可平凡复制要求,主要是文档层面的安全提示,而非编译器强制的编译错误。大多数编译器不会在实例化
boost::atomic<T>时就直接报错,只有当代码触发了依赖平凡复制的原子操作时,才可能出现未定义行为。 - 当前代码未执行危险的原子操作:示例代码仅创建了
boost::atomic<atom>对象,且只调用了std::is_trivially_copyable的检查,没有调用任何原子读写接口(比如load()、store()、exchange())。这些原子操作接口才会生成依赖平凡复制的代码,没有调用的话,自然不会触发未定义行为。 - 内存布局恰好满足临时运行条件:虽然
atom包含std::string,但如果整个结构体的大小和对齐方式刚好符合平台原子操作的要求(比如部分平台允许对任意对齐内存执行原子操作,或结构体大小恰好是原子指令支持的宽度),在未执行原子操作的情况下,程序能正常运行。但一旦调用原子读写,就会破坏std::string的内部堆内存状态,触发未定义行为。 - 编译器的宽容性:GCC、Clang等编译器对这类模板参数约束的检查并不严格,不会在实例化阶段就拦截非平凡复制类型的
boost::atomic<T>,甚至可能连警告都不会发出,这也导致代码能正常编译运行。
内容的提问来源于stack exchange,提问作者VoVAllen
相关产品推荐
相关产品推荐

