| Home | Libraries | People | FAQ | More

## Limitations

While Boost.Atomic strives to implement the atomic operations from C++11 and later as faithfully as possible, there are a few limitations that cannot be lifted without compiler support:

- Aggregate initialization syntax is not supported: Since Boost.Atomic sometimes uses storage type that is different from the value type, the `atomic<>` template needs an initialization constructor that performs the necessary conversion. This makes `atomic<>` a non-aggregate type and prohibits aggregate initialization syntax (`atomic<int> a = {10}`). Boost.Atomic does support direct and unified initialization syntax though. Advice: Always use direct initialization (`atomic<int> a(10)`) or unified initialization (`atomic<int> a{10}`) syntax.
- Initializing constructor is not `constexpr` for some types: For value types other than integral types and `bool`, `atomic<>` initializing constructor needs to perform runtime conversion to the storage type. This limitation may be lifted for more categories of types in the future.
- Default constructor is not trivial in C++03: Because the initializing constructor has to be defined in `atomic<>`, the default constructor must also be defined. In C++03 the constructor cannot be defined as defaulted and therefore it is not trivial. In C++11 the constructor is defaulted (and trivial, if the default constructor of the value type is). In any case, the default constructor of `atomic<>` performs default initialization of the atomic value, as required in C++11. Advice: In C++03, do not use Boost.Atomic in contexts where trivial default constructor is important (e.g. as a global variable which is required to be statically initialized).
- C++03 compilers may transform computation dependency to control dependency: Crucially, `memory_order_consume` only affects computationally-dependent operations, but in general there is nothing preventing a compiler from transforming a computation dependency into a control dependency. A fully compliant C++11 compiler would be forbidden from such a transformation, but in practice most if not all compilers have chosen to promote `memory_order_consume` to `memory_order_acquire` instead (see this gcc bug for example). In the current implementation Boost.Atomic follows that trend, but this may change in the future. Advice: In general, avoid `memory_order_consume` and use `memory_order_acquire` instead. Use `memory_order_consume` only in conjunction with pointer values, and only if you can ensure that the compiler cannot speculate and transform these into control dependencies.
- Fence operations may enforce "too strong" compiler ordering: Semantically, `memory_order_acquire`/`memory_order_consume` and `memory_order_release` need to restrain reordering of memory operations only in one direction. Since in C++03 there is no way to express this constraint to the compiler, these act as "full compiler barriers" in C++03 implementation. In corner cases this may result in a slightly less efficient code than a C++11 compiler could generate. Boost.Atomic will use compiler intrinsics, if possible, to express the proper ordering constraints.
- Atomic operations may enforce "too strong" memory ordering in debug mode: On some compilers, disabling optimizations makes it impossible to provide memory ordering constraints as compile-time constants to the compiler intrinsics. This causes the compiler to silently ignore the provided constraints and choose the "strongest" memory order (`memory_order_seq_cst`) to generate code. Not only this reduces performance, this may hide bugs in the user's code (e.g. if the user used a wrong memory order constraint, which caused a data race). Advice: Always test your code with optimizations enabled.
- No interprocess fallback: using `atomic<T>` in shared memory only works correctly, if `atomic<T>::is_lock_free() == true`. Same with `atomic_ref<T>`.
- Signed integers must use two's complement representation: Boost.Atomic makes this requirement in order to implement conversions between signed and unsigned integers internally. C++11 requires all atomic arithmetic operations on integers to be well defined according to two's complement arithmetics, which means that Boost.Atomic has to operate on unsigned integers internally to avoid undefined behavior that results from signed integer overflows. Platforms with other signed integer representations are not supported. Note that C++20 makes two's complement representation of signed integers mandatory.