Date: Thu, 12 Jun 2025 19:19:07 +0100
>Isn't that already covered in Paragraph 2?
Yes, that's exactly what it's saying, I'm responding to what you said after that (the quote at the start of my email) where you inferred that it means that an object passed by const ref being modified is forbidden, which I don't think follows from a strict reading (assuming the ref itself isn't const). I think this might all be besides the point wrt your confusion though.
>Assuming your above
>definition of `std::foo` was legal, I am even more confused how Herb
>Sutter derives from the cited rule (it didn't change substantially
>since C++11) that const implies thread-safe for all operations called
>on an object by the standard library.
I'm providing a very strict reading of the standard that is probably not what's intented, so you can just ignore it if you're just trying to make sense of what Herb's saying.
One way to think about thread safety is that all objects in C++ are logically either exclusively owned and read-write, or shared between multiple threads and are read-only. Thread safety is ensured as long as that isn't violated (with obvious exceptions for atomics and mutexes). I think Herb's train of logic is something like:
1) The standard library won't write to anything it can't reach via a non-const reference (the paragraph you're quoting)
2) Therefore anything reachable from a const reference can only be read from
3) Since it's safe for many threads to read from the same variable without synchronization, any const references passed to a standard library function won't cause a data race (assuming nobody else is writing to the referenced object)
4) Therefore const standard library functions are thread safe
There is that little caveat on the third step where those functions aren't completely thread safe (it would be impossible for them to be so) but they do prevent the biggest potential pitfall which would be a standard library function secretly modifying something which another thread might be reading from without synchronization.
He's probably not taking my ultra strict reading of the standard (which is fairly extreme, I imagine the intention would be that if you pass const T* then that's supposed to be considered a "const argument") and so if you take the standard at it's likely intention and not it's word then the above train of logic makes sense.
On 12 June 2025 15:49:16 BST, Marvin Williams <marvinwilliams95_at_[hidden]> wrote:
>On Thu, 2025-06-12 at 13:36 +0100, Jennifier Burnett wrote:
>> > What I'm reading into this is that it is UB if a standard library
>> > function calls a const member function of an object that was passed
>> > to
>> > it via a const ref, and the the const member function "modifies"
>> > the
>> > object (via const_cast or a mutable member).
>> > However, I doubt that this is the correct interpretation.
>>
>> I believe the clause is saying is that any object modified by the
>> standard library function must be derivable from it's non-const
>> arguments including the implicit this pointer (i.e. not derived from
>> a global), not that any const object derivable from the arguments
>> won't be modified.
>>
>> So it would be UB by the quoted clause for a standard library
>> function to for example:
>>
>> ```
>> int* global;
>>
>> int foo()
>> {
>> int a, b;
>> b = 2;
>> global = &b;
>> std::bar(&a);
>> return b + a;
>> }
>> void std::bar(int* ref)
>> {
>> *global = 0;
>> *ref = 5;
>> }
>> ```
>>
>> Because the access through `global` is not done indirectly through
>> the function's non-const arguments.
>>
>
>Isn't that already covered in Paragraph 2? It reads:
>"A C++ standard library function shall not directly or indirectly
>access objects ([intro.multithread]) accessible by threads other than
>the current thread unless the objects are accessed directly or
>indirectly via the function's arguments, including this."
>
>> If you had a function like this, however:
>>
>> ```
>> void std::foo(const int* ref)
>> {
>> *const_cast<int*>(ref) = 42;
>> }
>> ```
>>
>> That's fine by that clause, because the pointer argument itself is
>> non-const (just the object pointed to by it). If the object pointed
>> to by ref was declared as const that would be UB, but by a general
>> language rule and not by the clause you quote. So long as the object
>> pointed to by ref is ultimately mutable the clause seems to be fine
>> with it. In order to trigger the clause you'd need the signature to
>> be:
>>
>> ```
>> void std::foo(const int* const ref)
>> ```
>>
>> Because the access would be derived from a const argument. I'm not
>> sure that's the exact intention of the clause but that's what a
>> strict reading gives me.
>
>I agree with you that a `const int* p` is not technically a const
>argument (would a reference be a const argument?). Assuming your above
>definition of `std::foo` was legal, I am even more confused how Herb
>Sutter derives from the cited rule (it didn't change substantially
>since C++11) that const implies thread-safe for all operations called
>on an object by the standard library.
>
>Best
>Marvin
>
>>
>> On 12 June 2025 09:56:16 BST, Marvin Williams via Std-Discussion
>> <std-discussion_at_[hidden]> wrote:
>> > Hi all,
>> >
>> > in the current working draft, clause [res.on.data.races]
>> > (ยง16.4.6.10,
>> > https://eel.is/c++draft/res.on.data.races), which regards data race
>> > avoidance in the standard library implementation, states (Paragraph
>> > 3):
>> >
>> > "A C++ standard library function shall not directly or indirectly
>> > modify objects ([intro.multithread]) accessible by threads other
>> > than
>> > the current thread unless the objects are accessed directly or
>> > indirectly via the function's non-const arguments, including this."
>> >
>> > What I'm reading into this is that it is UB if a standard library
>> > function calls a const member function of an object that was passed
>> > to
>> > it via a const ref, and the the const member function "modifies"
>> > the
>> > object (via const_cast or a mutable member).
>> > However, I doubt that this is the correct interpretation.
>> >
>> > There is some discussion about this clause, but I couldn't find a
>> > definitive answer.
>> > Most notably, there is a talk by Herb Sutter:
>> > https://web.archive.org/web/20170119232617/https://channel9.msdn.com/posts/C-and-Beyond-2012-Herb-Sutter-You-dont-know-blank-and-blank
>> >
>> > At about 15:35, he states that since C++11, const implies
>> > threadsafe,
>> > because it implies either bitwise const or internal synchronization
>> > (e.g., by a mutable std::mutex).
>> >
>> > With the above interpretation, I can see how const may imply
>> > bitwise
>> > const, but I fail to see how Herb derives the internal
>> > synchronization
>> > requirement. In my understanding, the example given at 26:00,
>> > locking a
>> > mutable std::mutex member still modifies the object, violating
>> > [res.on.data.races], if a standard library function were to call
>> > w.get_info() on a const widget& w.
>> >
>> > My main questions are:
>> > What are the requirements for const member functions that are
>> > intended
>> > to be used with the standard library, and how does thread-safety
>> > relate
>> > to the const qualifier?
>> >
>> > Best
>> > Marvin
>> > --
>> > Std-Discussion mailing list
>> > Std-Discussion_at_[hidden]
>> > https://lists.isocpp.org/mailman/listinfo.cgi/std-discussion
Yes, that's exactly what it's saying, I'm responding to what you said after that (the quote at the start of my email) where you inferred that it means that an object passed by const ref being modified is forbidden, which I don't think follows from a strict reading (assuming the ref itself isn't const). I think this might all be besides the point wrt your confusion though.
>Assuming your above
>definition of `std::foo` was legal, I am even more confused how Herb
>Sutter derives from the cited rule (it didn't change substantially
>since C++11) that const implies thread-safe for all operations called
>on an object by the standard library.
I'm providing a very strict reading of the standard that is probably not what's intented, so you can just ignore it if you're just trying to make sense of what Herb's saying.
One way to think about thread safety is that all objects in C++ are logically either exclusively owned and read-write, or shared between multiple threads and are read-only. Thread safety is ensured as long as that isn't violated (with obvious exceptions for atomics and mutexes). I think Herb's train of logic is something like:
1) The standard library won't write to anything it can't reach via a non-const reference (the paragraph you're quoting)
2) Therefore anything reachable from a const reference can only be read from
3) Since it's safe for many threads to read from the same variable without synchronization, any const references passed to a standard library function won't cause a data race (assuming nobody else is writing to the referenced object)
4) Therefore const standard library functions are thread safe
There is that little caveat on the third step where those functions aren't completely thread safe (it would be impossible for them to be so) but they do prevent the biggest potential pitfall which would be a standard library function secretly modifying something which another thread might be reading from without synchronization.
He's probably not taking my ultra strict reading of the standard (which is fairly extreme, I imagine the intention would be that if you pass const T* then that's supposed to be considered a "const argument") and so if you take the standard at it's likely intention and not it's word then the above train of logic makes sense.
On 12 June 2025 15:49:16 BST, Marvin Williams <marvinwilliams95_at_[hidden]> wrote:
>On Thu, 2025-06-12 at 13:36 +0100, Jennifier Burnett wrote:
>> > What I'm reading into this is that it is UB if a standard library
>> > function calls a const member function of an object that was passed
>> > to
>> > it via a const ref, and the the const member function "modifies"
>> > the
>> > object (via const_cast or a mutable member).
>> > However, I doubt that this is the correct interpretation.
>>
>> I believe the clause is saying is that any object modified by the
>> standard library function must be derivable from it's non-const
>> arguments including the implicit this pointer (i.e. not derived from
>> a global), not that any const object derivable from the arguments
>> won't be modified.
>>
>> So it would be UB by the quoted clause for a standard library
>> function to for example:
>>
>> ```
>> int* global;
>>
>> int foo()
>> {
>> int a, b;
>> b = 2;
>> global = &b;
>> std::bar(&a);
>> return b + a;
>> }
>> void std::bar(int* ref)
>> {
>> *global = 0;
>> *ref = 5;
>> }
>> ```
>>
>> Because the access through `global` is not done indirectly through
>> the function's non-const arguments.
>>
>
>Isn't that already covered in Paragraph 2? It reads:
>"A C++ standard library function shall not directly or indirectly
>access objects ([intro.multithread]) accessible by threads other than
>the current thread unless the objects are accessed directly or
>indirectly via the function's arguments, including this."
>
>> If you had a function like this, however:
>>
>> ```
>> void std::foo(const int* ref)
>> {
>> *const_cast<int*>(ref) = 42;
>> }
>> ```
>>
>> That's fine by that clause, because the pointer argument itself is
>> non-const (just the object pointed to by it). If the object pointed
>> to by ref was declared as const that would be UB, but by a general
>> language rule and not by the clause you quote. So long as the object
>> pointed to by ref is ultimately mutable the clause seems to be fine
>> with it. In order to trigger the clause you'd need the signature to
>> be:
>>
>> ```
>> void std::foo(const int* const ref)
>> ```
>>
>> Because the access would be derived from a const argument. I'm not
>> sure that's the exact intention of the clause but that's what a
>> strict reading gives me.
>
>I agree with you that a `const int* p` is not technically a const
>argument (would a reference be a const argument?). Assuming your above
>definition of `std::foo` was legal, I am even more confused how Herb
>Sutter derives from the cited rule (it didn't change substantially
>since C++11) that const implies thread-safe for all operations called
>on an object by the standard library.
>
>Best
>Marvin
>
>>
>> On 12 June 2025 09:56:16 BST, Marvin Williams via Std-Discussion
>> <std-discussion_at_[hidden]> wrote:
>> > Hi all,
>> >
>> > in the current working draft, clause [res.on.data.races]
>> > (ยง16.4.6.10,
>> > https://eel.is/c++draft/res.on.data.races), which regards data race
>> > avoidance in the standard library implementation, states (Paragraph
>> > 3):
>> >
>> > "A C++ standard library function shall not directly or indirectly
>> > modify objects ([intro.multithread]) accessible by threads other
>> > than
>> > the current thread unless the objects are accessed directly or
>> > indirectly via the function's non-const arguments, including this."
>> >
>> > What I'm reading into this is that it is UB if a standard library
>> > function calls a const member function of an object that was passed
>> > to
>> > it via a const ref, and the the const member function "modifies"
>> > the
>> > object (via const_cast or a mutable member).
>> > However, I doubt that this is the correct interpretation.
>> >
>> > There is some discussion about this clause, but I couldn't find a
>> > definitive answer.
>> > Most notably, there is a talk by Herb Sutter:
>> > https://web.archive.org/web/20170119232617/https://channel9.msdn.com/posts/C-and-Beyond-2012-Herb-Sutter-You-dont-know-blank-and-blank
>> >
>> > At about 15:35, he states that since C++11, const implies
>> > threadsafe,
>> > because it implies either bitwise const or internal synchronization
>> > (e.g., by a mutable std::mutex).
>> >
>> > With the above interpretation, I can see how const may imply
>> > bitwise
>> > const, but I fail to see how Herb derives the internal
>> > synchronization
>> > requirement. In my understanding, the example given at 26:00,
>> > locking a
>> > mutable std::mutex member still modifies the object, violating
>> > [res.on.data.races], if a standard library function were to call
>> > w.get_info() on a const widget& w.
>> >
>> > My main questions are:
>> > What are the requirements for const member functions that are
>> > intended
>> > to be used with the standard library, and how does thread-safety
>> > relate
>> > to the const qualifier?
>> >
>> > Best
>> > Marvin
>> > --
>> > Std-Discussion mailing list
>> > Std-Discussion_at_[hidden]
>> > https://lists.isocpp.org/mailman/listinfo.cgi/std-discussion
Received on 2025-06-12 18:20:16