Date: Fri, 09 Oct 2026 10:46:13 +0100
Because the standard doesn't define it and an implementation isn't required to, nor is it required to ensure that any program that runs it has any sane behaviour.
When we're saying undefined we don't mean "undefined on all implementations", that's impossible to claim because it's trivial to create an implementation that defines any given piece of behaviour - GCC has a command line option to make integer overflow defined, for example, but that doesn't mean integer overflow isn't undefined. When people say a program has undefined behaviour really what they mean is that it is that unless the implementation goes out of it's way to make it defined (like with your volatiles or GCC's integers), it'll be undefined.
On 9 October 2026 10:22:28 BST, jim x <xmh970252187_at_[hidden]> wrote:
>The crux is: why do you think the program is undefined behavior without
>knowing the semantics of the access that would be specified by the concrete
>implementation? What's your reason for that?
>
>On Fri, Oct 9, 2026 at 5:03 PM Jennifier Burnett <jenni_at_[hidden]>
>wrote:
>
>> The crux of what I'm saying is that just because something is said to be
>> undefined in the standard doesn't make it undefined on a particular
>> implementation. In this hypothetical implementation accesses to volatile
>> variables are documented to be atomic, so [intro.race] p17 does not apply
>> and thus the behaviour is well-defined. A behaviour being defined by an
>> implementation is different from something being implementation-defined, if
>> that helps.
>>
>>
>> On 9 October 2026 08:55:52 BST, jim x <xmh970252187_at_[hidden]> wrote:
>>
>>> So, what behavior of the program do you think? If you think the program
>>> should be undefined behavior because the program contains a data race,
>>> let's step-by-step to go through the rules in [intro.race] p17. It's true
>>> that `#1` and `#2` are two potentially concurrent conflicting actions, and
>>> neither happens before the other. The crux is whether they satisfy the
>>> condition: at least one of which is not atomic. If one of them is
>>> non-atomic, then the condition is satisfied; therefore, the program
>>> contains a data race. If they are both atomic operations, the condition is
>>> false; no data race is contained. As I commented above, since the standard
>>> lets implementations define the semantics of the access, and a
>>> hypothetical implementation can define `#1` as `
>>> std::atomic_ref<int>(value).load()` and `#2` as `
>>> std::atomic_ref<int>(value).store(1)`; i.e., they're atomic operations,
>>> I don't think the crux condition in [intro.race] p17 is true. So, the
>>> program under this specified semantics shouldn't be UB. How do you explain
>>> this point?
>>>
>>> On Fri, Oct 9, 2026 at 3:39 PM David Brown <david.brown_at_[hidden]>
>>> wrote:
>>>
>>>>
>>>>
>>>> On 09/10/2026 09:16, jim x via Std-Discussion wrote:
>>>> > If the implementation defines that accesses to volatile variables
>>>> > are atomic, then they are atomic.
>>>> >
>>>> >
>>>> > In this case, does the program contain a data race as per [intro.race]
>>>> > p17? If not, since the behavior depends on how the implementation
>>>> define
>>>> > the semantics, does that mean the behavior of the program should be
>>>> > implementation-defined?
>>>> >
>>>>
>>>> "Implementation-defined" in the standards does not just mean that the
>>>> implementation has to treat the construct in some particular way. It
>>>> means that the standard gives a range of options of how the
>>>> implementation should handle the construct, and that the implementation
>>>> must document how it handles them.
>>>>
>>>> If an implementation's manual says that volatile accesses are atomic
>>>> (not unreasonable on single-core non-superscaler targets like most
>>>> microcontrollers), then the programmer can rely on the volatile accesses
>>>> being atomic. But that does not mean unsynchronised volatile accesses
>>>> to the same address in different threads is implementation-defined
>>>> behaviour, or should be called such in the C++ standards.
>>>>
>>>>
>>>>
When we're saying undefined we don't mean "undefined on all implementations", that's impossible to claim because it's trivial to create an implementation that defines any given piece of behaviour - GCC has a command line option to make integer overflow defined, for example, but that doesn't mean integer overflow isn't undefined. When people say a program has undefined behaviour really what they mean is that it is that unless the implementation goes out of it's way to make it defined (like with your volatiles or GCC's integers), it'll be undefined.
On 9 October 2026 10:22:28 BST, jim x <xmh970252187_at_[hidden]> wrote:
>The crux is: why do you think the program is undefined behavior without
>knowing the semantics of the access that would be specified by the concrete
>implementation? What's your reason for that?
>
>On Fri, Oct 9, 2026 at 5:03 PM Jennifier Burnett <jenni_at_[hidden]>
>wrote:
>
>> The crux of what I'm saying is that just because something is said to be
>> undefined in the standard doesn't make it undefined on a particular
>> implementation. In this hypothetical implementation accesses to volatile
>> variables are documented to be atomic, so [intro.race] p17 does not apply
>> and thus the behaviour is well-defined. A behaviour being defined by an
>> implementation is different from something being implementation-defined, if
>> that helps.
>>
>>
>> On 9 October 2026 08:55:52 BST, jim x <xmh970252187_at_[hidden]> wrote:
>>
>>> So, what behavior of the program do you think? If you think the program
>>> should be undefined behavior because the program contains a data race,
>>> let's step-by-step to go through the rules in [intro.race] p17. It's true
>>> that `#1` and `#2` are two potentially concurrent conflicting actions, and
>>> neither happens before the other. The crux is whether they satisfy the
>>> condition: at least one of which is not atomic. If one of them is
>>> non-atomic, then the condition is satisfied; therefore, the program
>>> contains a data race. If they are both atomic operations, the condition is
>>> false; no data race is contained. As I commented above, since the standard
>>> lets implementations define the semantics of the access, and a
>>> hypothetical implementation can define `#1` as `
>>> std::atomic_ref<int>(value).load()` and `#2` as `
>>> std::atomic_ref<int>(value).store(1)`; i.e., they're atomic operations,
>>> I don't think the crux condition in [intro.race] p17 is true. So, the
>>> program under this specified semantics shouldn't be UB. How do you explain
>>> this point?
>>>
>>> On Fri, Oct 9, 2026 at 3:39 PM David Brown <david.brown_at_[hidden]>
>>> wrote:
>>>
>>>>
>>>>
>>>> On 09/10/2026 09:16, jim x via Std-Discussion wrote:
>>>> > If the implementation defines that accesses to volatile variables
>>>> > are atomic, then they are atomic.
>>>> >
>>>> >
>>>> > In this case, does the program contain a data race as per [intro.race]
>>>> > p17? If not, since the behavior depends on how the implementation
>>>> define
>>>> > the semantics, does that mean the behavior of the program should be
>>>> > implementation-defined?
>>>> >
>>>>
>>>> "Implementation-defined" in the standards does not just mean that the
>>>> implementation has to treat the construct in some particular way. It
>>>> means that the standard gives a range of options of how the
>>>> implementation should handle the construct, and that the implementation
>>>> must document how it handles them.
>>>>
>>>> If an implementation's manual says that volatile accesses are atomic
>>>> (not unreasonable on single-core non-superscaler targets like most
>>>> microcontrollers), then the programmer can rely on the volatile accesses
>>>> being atomic. But that does not mean unsynchronised volatile accesses
>>>> to the same address in different threads is implementation-defined
>>>> behaviour, or should be called such in the C++ standards.
>>>>
>>>>
>>>>
Received on 2026-10-09 09:46:24
