Date: Sat, 10 Oct 2026 11:06:27 +0800
I didn't say the standard defined the undefined behavior in this way.
Undefined behavior is defined as:
behavior for which this document imposes no requirements
The standard explicitly specifies which operations cause the program to
have undefined behavior in its document. The crux is that you think this
program in this question has undefined behavior because the program
contains a data race, and whether a program contains a data race is stated
by [intro.race] p17, then we focus on the condition that *"at least one of
which is not atomic". *This is the key point I asked in this question: why
the semantics that are defined as equivalent to
`std::atomic_ref::load()/store()` are still not considered as atomic from
the perspective of the C++ standard under [intro.race] p17? In other
words, why do you think such defined semantics still satisfy the condition *"at
least one of which is not atomic"* such that the program is stated to
contain a data race? Can you explain this point?
On Sat, Oct 10, 2026 at 10:36 AM Andrey Semashev via Std-Discussion <
std-discussion_at_[hidden]> wrote:
> On 10 Oct 2026 04:44, jim x via Std-Discussion wrote:
> > In your code, your objects are /not/ atomic. You do not have atomic
> > accesses. Your (hypothetical or real) implementation says that
> > volatile accesses have the same semantics as atomic accesses - that
> > does not make them "atomic" in accordance with the C++ standard. C+
> > + atomic accesses are accesses using the classes and functions from
> > <atomic>.
> >
> > I have to say the standard didn't clearly define what "atomic" means,
> > which is LWG2506 <https://cplusplus.github.io/LWG/issue2506>.
> > Furthermore, even though we make the consensus that the operations
> > defined in <atomic> are atomic operations, my question is: since the
> > specific semantics for access through volatile glvalue are equivalent to
> > `|std::atomic_ref<int>(value).load()|` for read and `|
> > std::atomic_ref<int>(value).store(1)|` for write,
>
> But they are not. AFAIR, the standard prohibits certain optimizations
> and "out of thin air" operations on volatiles, but beyond that it
> doesn't impose any requirements on how the operations on them are
> carried out. In particular, it doesn't require loads and stores to be
> atomic and visible in any particular order between threads.
>
> > and both ` |
> > std::atomic_ref<int>|::load` and ` |std::atomic_ref<int>|::store` are
> > atomic operations defined <atomic>, why are `#1` and `#2`, under these
> > specified semantics, not considered atomic operations? This is my
> confusion.
>
> As was explained by other commenters, you're making a reverse
> assumption. An implementation is allowed to implement volatiles using
> atomic operations, and under that implementation the program you posted
> would behave as expected. However, in terms of the C++ standard, that
> program would still exhibit UB, because the standard only defines
> behavior in terms of the abstract machine and not any specific
> implementation. A different implementation could implement volatiles
> differently, which would break your program. If a program may work or
> break on different (conforming) implementations, this is UB by definition.
>
> --
> Std-Discussion mailing list
> Std-Discussion_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-discussion
>
Undefined behavior is defined as:
behavior for which this document imposes no requirements
The standard explicitly specifies which operations cause the program to
have undefined behavior in its document. The crux is that you think this
program in this question has undefined behavior because the program
contains a data race, and whether a program contains a data race is stated
by [intro.race] p17, then we focus on the condition that *"at least one of
which is not atomic". *This is the key point I asked in this question: why
the semantics that are defined as equivalent to
`std::atomic_ref::load()/store()` are still not considered as atomic from
the perspective of the C++ standard under [intro.race] p17? In other
words, why do you think such defined semantics still satisfy the condition *"at
least one of which is not atomic"* such that the program is stated to
contain a data race? Can you explain this point?
On Sat, Oct 10, 2026 at 10:36 AM Andrey Semashev via Std-Discussion <
std-discussion_at_[hidden]> wrote:
> On 10 Oct 2026 04:44, jim x via Std-Discussion wrote:
> > In your code, your objects are /not/ atomic. You do not have atomic
> > accesses. Your (hypothetical or real) implementation says that
> > volatile accesses have the same semantics as atomic accesses - that
> > does not make them "atomic" in accordance with the C++ standard. C+
> > + atomic accesses are accesses using the classes and functions from
> > <atomic>.
> >
> > I have to say the standard didn't clearly define what "atomic" means,
> > which is LWG2506 <https://cplusplus.github.io/LWG/issue2506>.
> > Furthermore, even though we make the consensus that the operations
> > defined in <atomic> are atomic operations, my question is: since the
> > specific semantics for access through volatile glvalue are equivalent to
> > `|std::atomic_ref<int>(value).load()|` for read and `|
> > std::atomic_ref<int>(value).store(1)|` for write,
>
> But they are not. AFAIR, the standard prohibits certain optimizations
> and "out of thin air" operations on volatiles, but beyond that it
> doesn't impose any requirements on how the operations on them are
> carried out. In particular, it doesn't require loads and stores to be
> atomic and visible in any particular order between threads.
>
> > and both ` |
> > std::atomic_ref<int>|::load` and ` |std::atomic_ref<int>|::store` are
> > atomic operations defined <atomic>, why are `#1` and `#2`, under these
> > specified semantics, not considered atomic operations? This is my
> confusion.
>
> As was explained by other commenters, you're making a reverse
> assumption. An implementation is allowed to implement volatiles using
> atomic operations, and under that implementation the program you posted
> would behave as expected. However, in terms of the C++ standard, that
> program would still exhibit UB, because the standard only defines
> behavior in terms of the abstract machine and not any specific
> implementation. A different implementation could implement volatiles
> differently, which would break your program. If a program may work or
> break on different (conforming) implementations, this is UB by definition.
>
> --
> Std-Discussion mailing list
> Std-Discussion_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-discussion
>
Received on 2026-10-10 03:06:45
