Date: Thu, 12 Jun 2025 13:36:16 +0100
>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.
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.
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
>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.
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.
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 12:37:26