Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Should you use constexpr by default?

193 views
Skip to first unread message

Juha Nieminen

unread,
Aug 21, 2018, 11:58:26 AM8/21/18
to
A good programming practice that has existed in C++ since the beginning
(or, more precisely, since this was supported) is to always make your
class member functions const by default, unless they really need to
modify the the contents of the object in question (or need to call
other non-const member functions).

(One way to follow this principle is "always put 'const' at the end
of member function declarations unless that makes it not compile.")

Personally I have gone even further with this "always use const by
default" principle (something that I was taught as a good practice):
Whenever I declare a function-local variable, I declare it const
unless I really need to modify it (again, same principle: "Make it
const unless that stops it from compiling.")

The idea with this is, of course, that it will catch unintentional
modifications of those variables.

Now that constexpr is a thing, I'm wondering if this principle should
be extended to that. Should all functions (and member functions) be
declared as 'constexpr' by default (unless that makes it not compile)?

I can't think of any drawbacks of this. If I understand correctly,
there can only be performance benefits from it, never drawbacks.
(Even if the constexprness never realizes itself at compile time,
you haven't lost anything in terms of performance.)

Öö Tiib

unread,
Aug 21, 2018, 1:45:44 PM8/21/18
to
On Tuesday, 21 August 2018 18:58:26 UTC+3, Juha Nieminen wrote:
> A good programming practice that has existed in C++ since the beginning
> (or, more precisely, since this was supported) is to always make your
> class member functions const by default, unless they really need to
> modify the the contents of the object in question (or need to call
> other non-const member functions).
>
> (One way to follow this principle is "always put 'const' at the end
> of member function declarations unless that makes it not compile.")
>
> Personally I have gone even further with this "always use const by
> default" principle (something that I was taught as a good practice):
> Whenever I declare a function-local variable, I declare it const
> unless I really need to modify it (again, same principle: "Make it
> const unless that stops it from compiling.")

That is very good principle to favor immutability where possible.

> The idea with this is, of course, that it will catch unintentional
> modifications of those variables.
>
> Now that constexpr is a thing, I'm wondering if this principle should
> be extended to that. Should all functions (and member functions) be
> declared as 'constexpr' by default (unless that makes it not compile)?
>
> I can't think of any drawbacks of this. If I understand correctly,
> there can only be performance benefits from it, never drawbacks.
> (Even if the constexprness never realizes itself at compile time,
> you haven't lost anything in terms of performance.)

In theory the constexpr lets to test and to catch defects
compile-time. So that can supposedly help us to fail faster.
OTOH in practice I have noticed that C++ compilers are slow when
running functions compile time. So simple functions that compiler will
likely inline and optimize anyway are OK to mark as constexpr but
deeper algorithms are cheaper to test with usual unit-tests and
keeping those non-constexpr in debug builds can speed development
process somewhat.

Vir Campestris

unread,
Aug 21, 2018, 3:58:08 PM8/21/18
to
On 21/08/2018 18:45, Öö Tiib wrote:
> In theory the constexpr lets to test and to catch defects
> compile-time. So that can supposedly help us to fail faster.
> OTOH in practice I have noticed that C++ compilers are slow when
> running functions compile time. So simple functions that compiler will
> likely inline and optimize anyway are OK to mark as constexpr but
> deeper algorithms are cheaper to test with usual unit-tests and
> keeping those non-constexpr in debug builds can speed development
> process somewhat.

Whether of course this is a problem or not depends entirely on your
environment.

We use Ice Cream distributed builds.

https://github.com/icecc/icecream

We've found that once you get past about 100 cores the improvements in
performance are minimal. That's 100 times parallel compilation, spread
around all the workstations in the office. The build times is down by
about 50 or so for the parallel parts, and 5 fold for the whole thing.
(we're now down to 10 minutes, which is little enough that we're not
bothering to try too hard to improve it).

OTOH that code is run on embedded ARM CPUs. Middle of the range ARMs,
not top end ones. So it's worth a bit of pain at build time.

Andy

Jorgen Grahn

unread,
Aug 22, 2018, 3:15:01 AM8/22/18
to
On Tue, 2018-08-21, Juha Nieminen wrote:
> A good programming practice that has existed in C++ since the beginning
> (or, more precisely, since this was supported) is to always make your
> class member functions const by default, unless they really need to
> modify the the contents of the object in question (or need to call
> other non-const member functions).
>
> (One way to follow this principle is "always put 'const' at the end
> of member function declarations unless that makes it not compile.")
>
> Personally I have gone even further with this "always use const by
> default" principle (something that I was taught as a good practice):
> Whenever I declare a function-local variable, I declare it const
> unless I really need to modify it (again, same principle: "Make it
> const unless that stops it from compiling.")
>
> The idea with this is, of course, that it will catch unintentional
> modifications of those variables.

I agree, of course, but I distrust "always" and the idea about doing
it almost mechanically. I want to write that 'const' only after
deciding "I don't think I'll want this to change".

Because, if I think about it for a second and still am unsure, it's a
sign that I don't have a clear plan for the function or class as a
whole. Then I should take a step back and think.

> Now that constexpr is a thing, I'm wondering if this principle should
> be extended to that. Should all functions (and member functions) be
> declared as 'constexpr' by default (unless that makes it not compile)?
>
> I can't think of any drawbacks of this. If I understand correctly,
> there can only be performance benefits from it, never drawbacks.
> (Even if the constexprness never realizes itself at compile time,
> you haven't lost anything in terms of performance.)

I /have/ noted that I almost never use constexpr. But whenever I
check a specific const, I seem to find making it constexpr wouldn't
buy me anything.

I don't want to go the way Alf went with the new-style function
signatures.

/Jorgen

--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .

James Kuyper

unread,
Aug 22, 2018, 6:45:59 AM8/22/18
to
On 08/22/2018 03:14 AM, Jorgen Grahn wrote:
> On Tue, 2018-08-21, Juha Nieminen wrote:
>> A good programming practice that has existed in C++ since the beginning
>> (or, more precisely, since this was supported) is to always make your
>> class member functions const by default, unless they really need to
>> modify the the contents of the object in question (or need to call
>> other non-const member functions).
>>
>> (One way to follow this principle is "always put 'const' at the end
>> of member function declarations unless that makes it not compile.")
>>
>> Personally I have gone even further with this "always use const by
>> default" principle (something that I was taught as a good practice):
>> Whenever I declare a function-local variable, I declare it const
>> unless I really need to modify it (again, same principle: "Make it
>> const unless that stops it from compiling.")
>>
>> The idea with this is, of course, that it will catch unintentional
>> modifications of those variables.
>
> I agree, of course, but I distrust "always" and the idea about doing
> it almost mechanically. I want to write that 'const' only after
> deciding "I don't think I'll want this to change".
>
> Because, if I think about it for a second and still am unsure, it's a
> sign that I don't have a clear plan for the function or class as a
> whole. Then I should take a step back and think.

I am, in general, a strong believer in planning ahead to avoid
difficulties. However, you have to look at the potential costs of
running into those difficulties, and compare them to the costs of
avoiding them, when deciding how much effort to put into planning. In
this case, the cost of running into those difficulties are quite small
if you default to 'const' whenever you're not sure.

In well-written C++ code, if you declare something to be 'const' that
actually needs to be modified, you're extremely likely, when you attempt
to compile the code that actually attempts to modify it, to get a
diagnostic that clearly identifies the problem. Upon seeing that
diagnostic, as always, you should consider whether to change the
offending code or the decision to declare the relevant identifier
'const'. It's trivial to remove the 'const' if that's the choice that
you make. There's even a small advantage to deferring this decision
until the diagnostic occurs: at that time, you'll know a lot more
details about how you're going to use the relevant identifier, and can
make a correspondingly better decision about whether it should be 'const'.

bitrex

unread,
Aug 22, 2018, 10:53:31 AM8/22/18
to
I'm ambivalent about this, in addition to allowing optimizations I think
"const" and "constexpr" should also express intent, that is to say a
constexpr class or method is one that is primarily intended to be
instantiated with/operate on data that is believed pretty likely to be
available at compile time e.g. template parameters.

By attaching "constexpr" to everything under the sun on the off chance
that something, somewhere, maybe be able to be optimized in a way you
didn't think of you lose intent in exchange for...what. Who can say
exactly. Maybe nothing.

It seems kind of like premature optimization and cargo-culty to me.

Öö Tiib

unread,
Aug 22, 2018, 1:56:53 PM8/22/18
to
On Tuesday, 21 August 2018 22:58:08 UTC+3, Vir Campestris wrote:
> On 21/08/2018 18:45, Öö Tiib wrote:
> > In theory the constexpr lets to test and to catch defects
> > compile-time. So that can supposedly help us to fail faster.
> > OTOH in practice I have noticed that C++ compilers are slow when
> > running functions compile time. So simple functions that compiler will
> > likely inline and optimize anyway are OK to mark as constexpr but
> > deeper algorithms are cheaper to test with usual unit-tests and
> > keeping those non-constexpr in debug builds can speed development
> > process somewhat.
>
> Whether of course this is a problem or not depends entirely on your
> environment.
>
> We use Ice Cream distributed builds.
>
> https://github.com/icecc/icecream
>
> We've found that once you get past about 100 cores the improvements in
> performance are minimal. That's 100 times parallel compilation, spread
> around all the workstations in the office. The build times is down by
> about 50 or so for the parallel parts, and 5 fold for the whole thing.
> (we're now down to 10 minutes, which is little enough that we're not
> bothering to try too hard to improve it).

Most often programmer does not really need most of that 500K SLOC
product compiled. He can work with single or few files (and unit
tests to those) locally. My experience is that non-trivial constexpr
algorithm can cause "compiling coffee-breaks" even in that
environment.

> OTOH that code is run on embedded ARM CPUs. Middle of the range ARMs,
> not top end ones. So it's worth a bit of pain at build time.

Constexpr can give impressive results at the end regardless of CPU.
Doing as much as possible compile-time in critical paths can boost
run-time performance by orders of magnitude. What I wanted to express
was that it does not usually help us to "fail faster" on incorrect
behavior.

Jorgen Grahn

unread,
Aug 23, 2018, 1:48:13 AM8/23/18
to
I think I meant to express this elsewhere in the thread; you did it
better.

> By attaching "constexpr" to everything under the sun on the off chance
> that something, somewhere, maybe be able to be optimized in a way you
> didn't think of you lose intent in exchange for...what. Who can say
> exactly. Maybe nothing.
>
> It seems kind of like premature optimization and cargo-culty to me.

I'd be interested to learn when I can benefit from constexpr, in the
kind of code I write. Looking at my hobby projects (which are more
about getting things done, than exploring C++ techniques) I find it in
four places, but it seems I used it unnecessarily as a glorified
const.

Juha Nieminen

unread,
Aug 23, 2018, 1:48:45 AM8/23/18
to
Jorgen Grahn <grahn...@snipabacken.se> wrote:
> I agree, of course, but I distrust "always" and the idea about doing
> it almost mechanically. I want to write that 'const' only after
> deciding "I don't think I'll want this to change".

In the case of function-local variables that's a way to think about it.

However, in the case of member functions, it's more than that.
Member functions should always be const by default, and non-const only
if that's the actual intent.

The public interface of a class tells the calling code, ie. the code
that's using that class, how it behaves. Moreover, it becomes very
practical due to the prevalence of using const references to objects
in many situations (nothing is more annoying than taking an object by
const reference and then not being able to call a member function that
*should* be const, but isn't.)

Even beyond that, in the era of C++11 and newer, the constness of
a member function should indicate that it's thread-safe to call it
without a locking mechanism.

Juha Nieminen

unread,
Aug 23, 2018, 3:18:27 AM8/23/18
to
Jorgen Grahn <grahn...@snipabacken.se> wrote:
> I'd be interested to learn when I can benefit from constexpr, in the
> kind of code I write. Looking at my hobby projects (which are more
> about getting things done, than exploring C++ techniques) I find it in
> four places, but it seems I used it unnecessarily as a glorified
> const.

I think that the plan for the next C++ standard to have the standard
data containers be constexpr-compatible is an example of where it
could be useful. This allows doing quite complicated calculations
at compile time.

There are many situations where you need to precalculate things
(sometimes even large amounts of data) to be hard-coded into the
program, rather than them being calculated at runtime. One common
traditional solution for this is writing a separate program that
does the calculations and outputs C++ source code into a file (which
is then compiled into the actual program at build time).

constexpr constructs would, to some extent, allow doing this within
the one and same source code, rather than have to use a secondary
independent program. The compiler would be generating the data, rather
than an external program. (Of course the drawback to this may be that
the calculations would need to be done every single time that source
code is recompiled, even if the calculated data itself remains the same.)

Of course that's not the only use for constexpr, but it's one of them.

Jorgen Grahn

unread,
Aug 23, 2018, 3:51:16 AM8/23/18
to
On Thu, 2018-08-23, Juha Nieminen wrote:
> Jorgen Grahn <grahn...@snipabacken.se> wrote:
>> I agree, of course, but I distrust "always" and the idea about doing
>> it almost mechanically. I want to write that 'const' only after
>> deciding "I don't think I'll want this to change".
>
> In the case of function-local variables that's a way to think about it.
>
> However, in the case of member functions, it's more than that.
> Member functions should always be const by default, and non-const only
> if that's the actual intent.

I agree, except with your wording ("always ... by default").
We mean the same thing: that you should know early if a member
function is const or non-const. And that "const" isn't just an
optional decoration.

IME, if you're not sure about such a member, you have an unclear
overall picture of the class, or you're unconciously in the process of
redesigning it.

bitrex

unread,
Aug 23, 2018, 4:44:52 AM8/23/18
to
On 08/21/2018 11:58 AM, Juha Nieminen wrote:
> A good programming practice that has existed in C++ since the beginning
> (or, more precisely, since this was supported) is to always make your
> class member functions const by default, unless they really need to
> modify the the contents of the object in question (or need to call
> other non-const member functions).
>
> (One way to follow this principle is "always put 'const' at the end
> of member function declarations unless that makes it not compile.")
>
> Personally I have gone even further with this "always use const by
> default" principle (something that I was taught as a good practice):
> Whenever I declare a function-local variable, I declare it const
> unless I really need to modify it (again, same principle: "Make it
> const unless that stops it from compiling.")
>
> The idea with this is, of course, that it will catch unintentional
> modifications of those variables.

The frustrating thing about const is that const-qualified class members
and move constructors don't play well together, but it seems that's
where one would see the most benefit re: optimization from
const-qualification. Yeah it's good practice to make all function-local
stack variables that aren't modified again const to express intent but
the modern optimizing compiler seems pretty good about sussing it out
and just inlining/load immediate stuff where appropriate in that
situation anyway.

Juha Nieminen

unread,
Aug 23, 2018, 6:17:27 AM8/23/18
to
bitrex <us...@example.net> wrote:
> The frustrating thing about const is that const-qualified class members
> and move constructors don't play well together, but it seems that's
> where one would see the most benefit re: optimization from
> const-qualification. Yeah it's good practice to make all function-local
> stack variables that aren't modified again const to express intent but
> the modern optimizing compiler seems pretty good about sussing it out
> and just inlining/load immediate stuff where appropriate in that
> situation anyway.

In the 90's there might have been some optimization benefits from
declaring all immutable stack variables as const, with some compilers
(as the constness might have worked a sort of hint to the compiler
to optimize the use of that variable), but that's probably not have
been the case for over a decade now, as you note.

However, my point wasn't about optimization of those stack variables
anyway... (In the end, whether you have the custom to declare them
const by default is more a question of style and coding conventions.
Personally I extraordinarily rarely find myself in a situation where
I inadvertently try to modify a variable when I'm not supposed to,
so even that "benefit" doesn't realize itself all that often. I still
use the convention, though. It's just a habit.)

woodb...@gmail.com

unread,
Aug 23, 2018, 1:46:36 PM8/23/18
to
It's nice to be able to agree with someone. Now I hope more
people will sign the east const petition:
http://slashslash.info/eastconst


Brian
Ebenezer Enterprises - Enjoying programming again.
https://github.com/Ebenezer-group/onwards

Öö Tiib

unread,
Aug 23, 2018, 1:56:26 PM8/23/18
to
On Thursday, 23 August 2018 10:18:27 UTC+3, Juha Nieminen wrote:
> Jorgen Grahn <grahn...@snipabacken.se> wrote:
> > I'd be interested to learn when I can benefit from constexpr, in the
> > kind of code I write. Looking at my hobby projects (which are more
> > about getting things done, than exploring C++ techniques) I find it in
> > four places, but it seems I used it unnecessarily as a glorified
> > const.
>
> I think that the plan for the next C++ standard to have the standard
> data containers be constexpr-compatible is an example of where it
> could be useful. This allows doing quite complicated calculations
> at compile time.

Actually std::duple, std::array, std::optional, std::variant and
std::string_view are already constexpr-compatible and these are
more than plenty to build as complex data structures that I can
only imagine compile-time. Also the outcome is quite convenient to
use but may be my imagination is lacking.

> There are many situations where you need to precalculate things
> (sometimes even large amounts of data) to be hard-coded into the
> program, rather than them being calculated at runtime. One common
> traditional solution for this is writing a separate program that
> does the calculations and outputs C++ source code into a file (which
> is then compiled into the actual program at build time).

Since the constexpr currently runs rather slowly that traditional way
is still strong alternative in practice. Constexpr is lot more pleasant
to read (and to debug) than complex template or preprocessor
metaprogramming so I believe that as soon as compilers improve the
compile-time speed I switch mostly to it.

> constexpr constructs would, to some extent, allow doing this within
> the one and same source code, rather than have to use a secondary
> independent program. The compiler would be generating the data, rather
> than an external program. (Of course the drawback to this may be that
> the calculations would need to be done every single time that source
> code is recompiled, even if the calculated data itself remains the same.)

That is indeed benefit of constexpr (same as with template or preprocessor
metaprogramming) that the build process with header-only things is most
simple while build process that involves building tools that generate
code is most complex.

Öö Tiib

unread,
Aug 23, 2018, 2:27:57 PM8/23/18
to
On Thursday, 23 August 2018 20:46:36 UTC+3, woodb...@gmail.com wrote:
>
> Now I hope more
> people will sign the east const petition:
> http://slashslash.info/eastconst

Is it petition of programmers who sit facing North when programming? :)


Left or Right const is somewhat matter of habit, mine happens to be
Right too. We could organize a competition who can provide best patch to
one of clang-format, AStyle, Uncrustify or GreatCode (are there others)
to add setting to reformat it as Left const or Right const. Then we would
be basically done with it?

Joining with that manifesto would benefit everybody better: https://utf8everywhere.org/
Unfortunately it is also harder. Major doers like Windows, Qt, Java,
C#, Python and ICU use some sort of UCS-2 or UTF-16 internally.

Alf P. Steinbach

unread,
Aug 23, 2018, 3:13:03 PM8/23/18
to
[Sorry, I inadvertently first sent this follow-up as a reply mail.]

On 23.08.2018 20:27, Öö Tiib wrote:
> On Thursday, 23 August 2018 20:46:36 UTC+3, woodb...@gmail.com wrote:
>>
>> Now I hope more
>> people will sign the east const petition:
>> http://slashslash.info/eastconst
>
> Is it petition of programmers who sit facing North when programming? :)


No, because consistent left `const` requires a supporting syntax that
lets you consistently place `const` left.

You can get that as a library solution by defining

template<class T> using ptr_ = T*;
template<class T> using ref_ = T&;

But replacing `*` and `&` with such notation is too much for a formatter.


> Left or Right const is somewhat matter of habit, mine happens to be
> Right too. We could organize a competition who can provide best patch to
> one of clang-format, AStyle, Uncrustify or GreatCode (are there others)
> to add setting to reformat it as Left const or Right const. Then we would
> be basically done with it?
>
> Joining with that manifesto would benefit everybody better: https://utf8everywhere.org/
> Unfortunately it is also harder. Major doers like Windows, Qt, Java,
> C#, Python and ICU use some sort of UCS-2 or UTF-16 internally.


As I recall the manifesto is full of disinformation and unsubstantiated,
sometimes directly incorrect, claims. I.e. it's propaganda. It just
/looks/ technical.

In spite of the manifesto I think UTF-8 is the way to go now, after
Visual C++ got support, but the support in Windows, for both g++ and
Visual C++, is very incomplete.

In particular,

1 with both g++ and Visual C++ the `main` arguments are encoded as
Windows ANSI,

2 there's no reasonably direct way to get UTF-8 console i/o (though one
can use libraries like my header only ¹Wrapped stdlib), and

3 the standard library, e.g. `isspace`, is based on an assumption of
fixed length encoding.

Also, UTF-8 is /easy to get wrong and difficult to get right/ with
std::filesystem, which is designed with an assumption of Windows ANSI
narrow encoding in Windows. So we need a kind of UTF-8 oriented wrapper.
If anyone feels up to the task?

Cheers!,

- Alf


Links:
¹ https://github.com/alf-p-steinbach/Wrapped-stdlib

bitrex

unread,
Aug 23, 2018, 3:29:20 PM8/23/18
to
I've seen it used extensively in say a fixed-point math library as an
example, you have say some base class called say FixedPoint that defines
an interface and though your fundamental type is say a 32 bit integer
you might want an UnsignedFixedPoint<16,16> number with 16 integer bits
and 16 fractional, or SignedFixedPoint<18, 14>, or whatever.

"Under the hood" however everything is just represented by a word of
some bits, the processor doesn't care what it is. What it "is" is
defined entirely by its construction and particular way the operator
overloads are carried out, how much you shift when doing a multiply or w/e.

So you can just constexpr all that and if all goes well all the
appropriate operations for conversion and manipulation will be inlined
at compile-time, any immediate fixed-point type which is known at
compile-time will be generated appropriately, and there will be little
run-time overhead. The interface can probably even be CRTPed/static
polymorphism to avoid virtual call overhead, too.

bitrex

unread,
Aug 23, 2018, 3:35:06 PM8/23/18
to
On 08/23/2018 03:29 PM, bitrex wrote:
> On 08/23/2018 01:48 AM, Jorgen Grahn wrote:
>> On Wed, 2018-08-22, bitrex wrote:
>>> On 08/21/2018 11:58 AM, Juha Nieminen wrote:
>>>> A good programming practice that has existed in C++ since the beginning
>>>> (or, more precisely, since this was supported) is to always make your
>>>> class member functions const by default, unless they really need to
>>>> modify the the contents of the object in question (or need to call
>>>> other non-const member functions).
>>>>
>>>> (One way to follow this principle is "always put 'const' at the end
>>>> of member function declarations unless that makes it not compile.")
>>>>
>>>> Personally I have gone even further with this "always use const by
>>>> default" principle (something that I was taught as a good practice):
>>>> Whenever I declare a function-local variable, I declare it const
>>>> unless I really need to modify it (again, same principle: "Make it
>>>> const unless that stops it from compiling.")
>>>>
>>>> The idea with this is, of course, that it will catch unintentional
>>>> modifications of those variables.
>>>>
>>>> Now that constexpr is a thing, I'm wondering if this principle should
>>>> be extended to that. Should all functions (and member functions) be
>>>> declared as 'constexpr' by default (unless that makes it not compile)?
>>>>+
it's good to remember that you can constexpr lots of stuff, including
operator overloads and constructors. C++11 is a little restrictive in
what you can do there but anything after that you're more free

bitrex

unread,
Aug 23, 2018, 3:38:01 PM8/23/18
to
Post C++11 it's pretty dead-simple to generate entire lookup tables at
compile-time using templates and constexpr. It's a little more tricky
with C++11's tighter restrictions on constexpr but can still be done.

bitrex

unread,
Aug 23, 2018, 3:50:17 PM8/23/18
to
Const pointers to mutable data make plenty of sense to me, but what do
when you want to write a move constructor for a class holding such a
pointer where the default-generated move constructor won't work for you.
You want to be able to assign the "other" class pointer to nullptr in
the move constructor body but can't, const-qualified pointers to mutable
data can only be modified in the initializer list.

Which is friggin' annoying because a const pointer to mustable data is
often just what you'd like to use in a move-only class, to enforce the
notion that this class is only reference-keeping for that member and not
actually copying data around. And unique ptr is not always appropriate
or even available.

Daniel

unread,
Aug 23, 2018, 3:50:27 PM8/23/18
to
On Thursday, August 23, 2018 at 1:48:45 AM UTC-4, Juha Nieminen wrote:
>
> the constness of a member function should indicate that it's thread-safe to
> call it without a locking mechanism.

But "f() const" doesn't indicate that at all. You can't make any assumptions about whether f mutates state.

Daniel

Richard

unread,
Aug 23, 2018, 5:16:40 PM8/23/18
to
[Please do not mail me a copy of your followup]

Jorgen Grahn <grahn...@snipabacken.se> spake the secret code
<slrnpnsnh9.31...@frailea.sa.invalid> thusly:

>We mean the same thing: that you should know early if a member
>function is const or non-const. And that "const" isn't just an
>optional decoration.
>
>IME, if you're not sure about such a member, you have an unclear
>overall picture of the class, or you're unconciously in the process of
>redesigning it.

+1

Most of the places where I see difficulty with the use of const on
members is that the class design doesn't follow Command/Query
Separation design guideline.
<https://martinfowler.com/bliki/CommandQuerySeparation.html>
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Terminals Wiki <http://terminals-wiki.org>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>

Vir Campestris

unread,
Aug 23, 2018, 6:13:48 PM8/23/18
to
On 23/08/2018 18:46, woodb...@gmail.com wrote:
> It's nice to be able to agree with someone. Now I hope more
> people will sign the east const petition:
> http://slashslash.info/eastconst

Elsewhere we were talking about defects in the language. IMHO this is
one of them, along with the fact that

char* a,b;

declares two variables of different types.

I dare say back in the distant past this wasn't seen as a problem.

And constexpr? Like const, it should have been the default.

But it isn't, and we have to live with it.

Andy

Öö Tiib

unread,
Aug 23, 2018, 6:19:08 PM8/23/18
to
On Thursday, 23 August 2018 22:13:03 UTC+3, Alf P. Steinbach wrote:
> [Sorry, I inadvertently first sent this follow-up as a reply mail.]

I use that mail box for registration (or resetting a password I
forgot) to random sites and so look into it rather rarely. Also
I have absent-mindedly cleaned it sometimes without reading anything.

> On 23.08.2018 20:27, Öö Tiib wrote:
> > On Thursday, 23 August 2018 20:46:36 UTC+3, woodb...@gmail.com wrote:
> >>
> >> Now I hope more
> >> people will sign the east const petition:
> >> http://slashslash.info/eastconst
> >
> > Is it petition of programmers who sit facing North when programming? :)
>
>
> No, because consistent left `const` requires a supporting syntax that
> lets you consistently place `const` left.
>
> You can get that as a library solution by defining
>
> template<class T> using ptr_ = T*;
> template<class T> using ref_ = T&;
>
> But replacing `*` and `&` with such notation is too much for a formatter.

I can perhaps persuade team to accept ban to typedefing raw pointers
whatsoever but these ptr_<T> and ref_<T> are likely outside of my
abilities to convince people.

> > Left or Right const is somewhat matter of habit, mine happens to be
> > Right too. We could organize a competition who can provide best patch to
> > one of clang-format, AStyle, Uncrustify or GreatCode (are there others)
> > to add setting to reformat it as Left const or Right const. Then we would
> > be basically done with it?
> >
> > Joining with that manifesto would benefit everybody better: https://utf8everywhere.org/
> > Unfortunately it is also harder. Major doers like Windows, Qt, Java,
> > C#, Python and ICU use some sort of UCS-2 or UTF-16 internally.
>
>
> As I recall the manifesto is full of disinformation and unsubstantiated,
> sometimes directly incorrect, claims. I.e. it's propaganda. It just
> /looks/ technical.
>
> In spite of the manifesto I think UTF-8 is the way to go now, after
> Visual C++ got support, but the support in Windows, for both g++ and
> Visual C++, is very incomplete.

Yes, it is indeed political. Very lot of text out there is UTF8.
https://w3techs.com/technologies/details/en-utf8/all/all
So tools that do not comply with UTF8 will share the fate of tools
that used RADIX50, EBCDIC and what were there by that trend.

> In particular,
>
> 1 with both g++ and Visual C++ the `main` arguments are encoded as
> Windows ANSI,

Yes, something like

echo 生きるか死ぬか

likely results with something like

生きるか死ぬか

So one has perhaps to Base64 a text to provide it as command line
argument in Windows.

> 2 there's no reasonably direct way to get UTF-8 console i/o (though one
> can use libraries like my header only ¹Wrapped stdlib), and

Thank you.

> 3 the standard library, e.g. `isspace`, is based on an assumption of
> fixed length encoding.

Figuring boundaries between words in text is rather non-trivial task.
Existence of `isspace` is illusion of it being doable simply.

> Also, UTF-8 is /easy to get wrong and difficult to get right/ with
> std::filesystem, which is designed with an assumption of Windows ANSI
> narrow encoding in Windows. So we need a kind of UTF-8 oriented wrapper.
> If anyone feels up to the task?

I have dropped any attempts in that direction since lot of tools
(including Microsoft's own) will choke at Unicode file names.
Perhaps real thing would be to rewrite ICU as header-only using
constexpr en masse to help C++ itself? Would be titanic task.

Öö Tiib

unread,
Aug 23, 2018, 6:33:53 PM8/23/18
to
I may be wrong but I got feeling that Juha was talking about a sane
agreement between developers what a const should indicate and not
what language should guarantee.

Otherwise yes C++ has well-formed ways to mutate data through const
pointer or to access private data of object. So language guarantees
nothing.

Juha Nieminen

unread,
Aug 24, 2018, 4:18:15 AM8/24/18
to
I said "should", not "does". And it's not my idea. It's the idea of
people quite high up in the C++ design/standardization process.

Optimally, programs written in C++11 and prior should be designed so
that a const member function means it's thread-safe.

Reinhardt Behm

unread,
Aug 24, 2018, 4:39:26 AM8/24/18
to
A const member function only promises that it itself will not to change the
object. That does not mean it will not be changed from another thread.
So the promise is not that it does not change because the function has no
control of this.

--
Reinhardt

Paavo Helde

unread,
Aug 24, 2018, 8:03:41 AM8/24/18
to
On 24.08.2018 11:39, Reinhardt Behm wrote:
> AT Friday 24 August 2018 16:18, Juha Nieminen wrote:
>> Optimally, programs written in C++11 and prior should be designed so
>> that a const member function means it's thread-safe.
>
> A const member function only promises that it itself will not to change the
> object.

No, it does not promise that. In particular, the 'mutable' keyword
exists precisely for allowing const member functions to change data.

What Juha is talking about (I think) is that if a const member function
changes anything then it should do this under an appropriate internal
mutex lock or equivalent.

> That does not mean it will not be changed from another thread.
> So the promise is not that it does not change because the function has no
> control of this.

Sure, in this approach one needs to apply an external lock in all
threads if one wants to call any non-const member function in some thread.

This is how STL containers like std::string and std::vector work, for
example.

Richard Damon

unread,
Aug 24, 2018, 8:54:00 AM8/24/18
to
On 8/21/18 11:58 AM, Juha Nieminen wrote:
> A good programming practice that has existed in C++ since the beginning
> (or, more precisely, since this was supported) is to always make your
> class member functions const by default, unless they really need to
> modify the the contents of the object in question (or need to call
> other non-const member functions).
>
> (One way to follow this principle is "always put 'const' at the end
> of member function declarations unless that makes it not compile.")
>
> Personally I have gone even further with this "always use const by
> default" principle (something that I was taught as a good practice):
> Whenever I declare a function-local variable, I declare it const
> unless I really need to modify it (again, same principle: "Make it
> const unless that stops it from compiling.")
>
> The idea with this is, of course, that it will catch unintentional
> modifications of those variables.
>
> Now that constexpr is a thing, I'm wondering if this principle should
> be extended to that. Should all functions (and member functions) be
> declared as 'constexpr' by default (unless that makes it not compile)?
>
> I can't think of any drawbacks of this. If I understand correctly,
> there can only be performance benefits from it, never drawbacks.
> (Even if the constexprness never realizes itself at compile time,
> you haven't lost anything in terms of performance.)
>

My one thought is that with this sort of rule it will lead to lasy
thinking. When you create a function/variable, you should KNOW if it is
supposed to be constant or variable. If it should be constant, make it
const/constexpr. If not (but perhaps for now might be) don't. That way
you catch both types of errors, changing something that should be const,
or depending on something to be const that isn't really. Getting in the
habit of just removing the const because it causes an error says that
you may miss some mistakes of changing something that should have been
const because the error is no longer an 'error' in your mind, just a
flag to make a change. Marking thing const that shouldn't be (and this
is more apt to be a problem with functions than variables) means you may
use something as const when it shouldn't be, and then later when you
want to make it non-const, you find that you can't as that makes other
errors where it was assumed to be const.

At the interface, const/non-const is an active part of the interface and
needs to be carefully thought of, as a change IS an interface change.

Internals may be less important, with less far reaching issues, but
still really should be though of ahead of time, and changes be
deliberate, and not just to silence errors/warnings.

constexpr works the same way. Marking something constexpr that isn't
fundamentally so, but just happens to be, allows it to be used in ways
that it shouldn't be, and constrains future modifications that might
have been intended.

Daniel

unread,
Aug 24, 2018, 9:03:16 AM8/24/18
to
On Friday, August 24, 2018 at 4:39:26 AM UTC-4, Reinhardt Behm wrote:
>
> A const member function only promises that it itself will not to change the
> object.

But const happily allows

struct A
{
int* p;

A()
{
p = new int[2];
}

void f() const
{
p[0] = 1;
}
};

int main()
{
A a;
a.f();
}

Daniel

bol...@cylonhq.com

unread,
Aug 24, 2018, 9:56:45 AM8/24/18
to
On Fri, 24 Aug 2018 06:03:02 -0700 (PDT)
Daniel <daniel...@gmail.com> wrote:
>On Friday, August 24, 2018 at 4:39:26 AM UTC-4, Reinhardt Behm wrote:
>>
>> A const member function only promises that it itself will not to change the
>> object.
>
>But const happily allows

Which is why I rarely both with this syntactic sugar - too many exceptions.
Far better to make sure any future programmers read the code rather than just
assuming IMO.

bitrex

unread,
Aug 24, 2018, 10:21:17 AM8/24/18
to
I agree, for example if there were only benefits and no drawbacks why
not just make "constexpr" the default behavior for everything in the
standard and make the programmer un-constexpr what they didn't want to
have that behavior with some keyword like marking functions "mutable"
or something.

Don't see any reason intrinsically it couldn't be that way other than
there are better reasons to have it the way it is than that way.

Mr Flibble

unread,
Aug 24, 2018, 11:00:38 AM8/24/18
to
Of course it should happily allow that and I see no problem with that.

/Flibble

--
"Suppose it’s all true, and you walk up to the pearly gates, and are
confronted by God," Bryne asked on his show The Meaning of Life. "What
will Stephen Fry say to him, her, or it?"
"I’d say, bone cancer in children? What’s that about?" Fry replied.
"How dare you? How dare you create a world to which there is such misery
that is not our fault. It’s not right, it’s utterly, utterly evil."
"Why should I respect a capricious, mean-minded, stupid God who creates a
world that is so full of injustice and pain. That’s what I would say."

Reinhardt Behm

unread,
Aug 24, 2018, 12:06:54 PM8/24/18
to
p[0] is not part of A, only p, and that is not changed.

--
Reinhardt

Daniel

unread,
Aug 24, 2018, 2:28:20 PM8/24/18
to
On Friday, August 24, 2018 at 12:06:54 PM UTC-4, Reinhardt Behm wrote:
> AT Friday 24 August 2018 21:03, Daniel wrote:
> >
> > But const happily allows
> >
> > struct A
> > {
> > int* p;
> >
> > A()
> > {
> > p = new int[2];
> > }
> >
> > void f() const
> > {
> > p[0] = 1;
> > }
> > };
> >
> > int main()
> > {
> > A a;
> > a.f();
> > }
>
> p[0] is not part of A, only p, and that is not changed.
>
p[0] is state that is owned by the instance a, and allowing that state to be mutated precludes reasoning about f() const in the same way as reasoning about a pure function. In particular, the ability to draw conclusions about thread safety goes out the window.

f() const has a well defined meaning, but that meaning does not correspond to that of a pure function, and it's unclear what the benefits are compared to pure. Its meaning seems to me to be mostly formal.

Daniel

Daniel

unread,
Aug 24, 2018, 3:21:58 PM8/24/18
to
On Friday, August 24, 2018 at 11:00:38 AM UTC-4, Mr Flibble wrote:
>
> Of course it should happily allow that and I see no problem with that.
>
The issue is that by looking at a function signature, say,

size_t size() const;

neither you (nor the compiler) can conclude anything about whether size() const is or is not mutating. Whether the data member is stored in size_t size_ or in size_t* size_ is an implementation detail that is neither here nor there. This greatly reduces the value of the const qualifier, to the point where it's merely suggestive, nothing more.

Daniel

Richard Damon

unread,
Aug 24, 2018, 7:31:30 PM8/24/18
to
const member functions are simply not allowed to modify (non-mutable)
members IN the structure. Data in affiliated structures is not protected.

Yes, this says that 'const' is not a total concept of the 'value' of a
structure, but doesn't make it worthless, just maybe worth less than it
could be.

Whether the constness of the object should pass to the things it points
to is very much dependent on context. I suppose it might be useful to
have some attribute on a pointer to make the constness of the data
pointed inherit from the constness of the object the pointer is in to
allow it to be specified on a case by case basis.

Richard Damon

unread,
Aug 24, 2018, 7:35:27 PM8/24/18
to
On 8/24/18 10:21 AM, bitrex wrote:
>
> I agree, for example if there were only benefits and no drawbacks why
> not just make "constexpr" the default behavior for everything in the
> standard and make the programmer un-constexpr what they didn't want to
> have that behavior with some keyword like  marking functions "mutable"
> or something.
>
> Don't see any reason intrinsically it couldn't be that way other than
> there are better reasons to have it the way it is than that way.

The biggest reason to not be const by default is backwards
comparability. To change the default mutability of variables would break
nearly every non-const declaration (the only ones it wouldn;t break are
those that could have been const).

Chris Vine

unread,
Aug 24, 2018, 8:38:47 PM8/24/18
to
On Thu, 23 Aug 2018 05:48:38 -0000 (UTC)
Juha Nieminen <nos...@thanks.invalid> wrote:
> Even beyond that, in the era of C++11 and newer, the constness of
> a member function should indicate that it's thread-safe to call it
> without a locking mechanism.

It absolutely doesn't mean that. Locking of object (instance) data is
required in a const member function if it accesses those data at a time
when a non-const member function might concurrently mutate the data in
another thread.

You may have got this idea from a talk given by Herb Sutter in which he
asserted that "const means thread safe". It doesn't.

A const member function can also mutate static data.

Juha Nieminen

unread,
Aug 25, 2018, 4:01:46 AM8/25/18
to
Reinhardt Behm <rb...@hushmail.com> wrote:
>> Optimally, programs written in C++11 and prior should be designed so
>> that a const member function means it's thread-safe.
>
> A const member function only promises that it itself will not to change the
> object. That does not mean it will not be changed from another thread.
> So the promise is not that it does not change because the function has no
> control of this.

What being "thread-safe" means in this case is that two threads can
safely call that function without problems. It's not a guarantee that
if one thread calls *another* function of the class then *this* function
will behave properly.

This is in contrast with non-const member functions: Two threads cannot
safely call said function without a locking mechanism (unless the
description of the function guarantees that it's thread-safe, of course).

In general, from C++11 forward you should design your const member
functions in this manner. 'const' ought to be a promise that it can
be safely called from multiple threads.

Juha Nieminen

unread,
Aug 25, 2018, 4:06:55 AM8/25/18
to
Chris Vine <chris@cvine--nospam--.freeserve.co.uk> wrote:
> On Thu, 23 Aug 2018 05:48:38 -0000 (UTC)
> Juha Nieminen <nos...@thanks.invalid> wrote:
>> Even beyond that, in the era of C++11 and newer, the constness of
>> a member function should indicate that it's thread-safe to call it
>> without a locking mechanism.
>
> It absolutely doesn't mean that. Locking of object (instance) data is
> required in a const member function if it accesses those data at a time
> when a non-const member function might concurrently mutate the data in
> another thread.

Thread-safety in this case means that two threads can call *that* function
in question without problems. It does *not* refer to on thread calling
const function A, and another thread calling a non-const function B at
the same time.

> You may have got this idea from a talk given by Herb Sutter in which he
> asserted that "const means thread safe". It doesn't.

I don't usually resort to argument for authority, but in this case I'm
making an exception.

> A const member function can also mutate static data.

And it really shouldn't. That's the point.

(Why does nodoby understand the difference between the words "should"
and "does"? Read my original text again, which you quoted above.)

Chris Vine

unread,
Aug 25, 2018, 11:29:37 AM8/25/18
to
On Sat, 25 Aug 2018 08:06:47 -0000 (UTC)
Juha Nieminen <nos...@thanks.invalid> wrote:
> Chris Vine <chris@cvine--nospam--.freeserve.co.uk> wrote:
> > On Thu, 23 Aug 2018 05:48:38 -0000 (UTC)
> > Juha Nieminen <nos...@thanks.invalid> wrote:
> >> Even beyond that, in the era of C++11 and newer, the constness of
> >> a member function should indicate that it's thread-safe to call it
> >> without a locking mechanism.
> >
> > It absolutely doesn't mean that. Locking of object (instance) data is
> > required in a const member function if it accesses those data at a time
> > when a non-const member function might concurrently mutate the data in
> > another thread.
>
> Thread-safety in this case means that two threads can call *that* function
> in question without problems. It does *not* refer to on thread calling
> const function A, and another thread calling a non-const function B at
> the same time.

What you said was:

"Even beyond that, in the era of C++11 and newer, the constness of a
member function should indicate that it's thread-safe to call it
without a locking mechanism."

That is just plain wrong. The only way of finding that out is to
inspect the code and its documentation. It is not sufficient to
examine the signatures of the const functions to check that they are
indeed marked 'const'. You have to see if any of the data accessed by
the const function(s) can be concurrently mutated by other threads.

> > You may have got this idea from a talk given by Herb Sutter in which he
> > asserted that "const means thread safe". It doesn't.
>
> I don't usually resort to argument for authority, but in this case I'm
> making an exception.
>
> > A const member function can also mutate static data.
>
> And it really shouldn't. That's the point.
>
> (Why does nodoby understand the difference between the words "should"
> and "does"? Read my original text again, which you quoted above.)

I wasn't discussing whether a const member function _should_ be able to
mutate global and static data. My point was that according to the C++
standard it _can_, which is another reason why calling const member
functions is NOT automatically thread safe by virtue of the fact that
they are marked const.

Juha Nieminen

unread,
Aug 25, 2018, 1:47:59 PM8/25/18
to
Chris Vine <chris@cvine--nospam--.freeserve.co.uk> wrote:
> What you said was:
>
> "Even beyond that, in the era of C++11 and newer, the constness of a
> member function should indicate that it's thread-safe to call it
> without a locking mechanism."
>
> That is just plain wrong. The only way of finding that out is to
> inspect the code and its documentation. It is not sufficient to
> examine the signatures of the const functions to check that they are
> indeed marked 'const'. You have to see if any of the data accessed by
> the const function(s) can be concurrently mutated by other threads.

Do you have trouble understanding what the word "should" means?

The constness of a member function SHOULD indicate that it's thread-safe.
SHOULD. Not "does". As in, you ought to implement the method so that
it's thread-safe to call it, as a good programming practice.

What other word can I use to make it clearer?

> I wasn't discussing whether a const member function _should_ be able to
> mutate global and static data.

But I was.

Chris Vine

unread,
Aug 25, 2018, 2:14:27 PM8/25/18
to
On Sat, 25 Aug 2018 17:47:46 -0000 (UTC)
Juha Nieminen <nos...@thanks.invalid> wrote:

> Chris Vine <chris@cvine--nospam--.freeserve.co.uk> wrote:
> > What you said was:
> >
> > "Even beyond that, in the era of C++11 and newer, the constness of a
> > member function should indicate that it's thread-safe to call it
> > without a locking mechanism."
> >
> > That is just plain wrong. The only way of finding that out is to
> > inspect the code and its documentation. It is not sufficient to
> > examine the signatures of the const functions to check that they are
> > indeed marked 'const'. You have to see if any of the data accessed by
> > the const function(s) can be concurrently mutated by other threads.
>
> Do you have trouble understanding what the word "should" means?
>
> The constness of a member function SHOULD indicate that it's thread-safe.
> SHOULD. Not "does". As in, you ought to implement the method so that
> it's thread-safe to call it, as a good programming practice.
>
> What other word can I use to make it clearer?

So what you are really proposing is a coding standard. You propose that
any member function which is labeled 'const' "should", in order to
comply with your standard, also be thread safe, so that if the object
concerned can be mutated concurrently in another thread, it should also
be protected by an internal mutex or similar internal synchronisation.

The standard library doesn't guarantee that, so I think you are onto a
loser. It would also be unnecessarily inefficient. All that the C++
standard guarantees is that a const member function can safely be
called concurrently with another thread calling that or another const
member function on the same object, provided that no non-const member
function is called concurrently on the object. Otherwise "a locking
mechanism" (your words) is required when invoking the const member
functions (and any non-const member function).

In order to describe a function as "thread safe" you must be able to
call it safely in one thread irrespective of what another thread is
doing. What "thread safe" means is that you do not have to provide
external synchronisation.

The fact is that no code that I know of complies with your coding
standard for 'const'. So it may be true that in your opinion "the
constness of a member function should indicate that it's thread-safe to
call it without a locking mechanism", in the real world the standard
library doesn't do so, so it doesn't.

Juha Nieminen

unread,
Aug 26, 2018, 1:29:59 AM8/26/18
to
Chris Vine <chris@cvine--nospam--.freeserve.co.uk> wrote:
> So what you are really proposing is a coding standard.

No, it's not me who is proposing it.

> The standard library doesn't guarantee that, so I think you are onto a
> loser. It would also be unnecessarily inefficient. All that the C++
> standard guarantees is that a const member function can safely be
> called concurrently with another thread calling that or another const
> member function on the same object, provided that no non-const member
> function is called concurrently on the object. Otherwise "a locking
> mechanism" (your words) is required when invoking the const member
> functions (and any non-const member function).

You proceeded to describe exactly what I was talking about.

> In order to describe a function as "thread safe" you must be able to
> call it safely in one thread irrespective of what another thread is
> doing. What "thread safe" means is that you do not have to provide
> external synchronisation.

So now you start nitpicking about the exact terminology. Right.

Chris Vine

unread,
Aug 26, 2018, 5:44:06 AM8/26/18
to
On Sun, 26 Aug 2018 05:29:47 -0000 (UTC)
Juha Nieminen <nos...@thanks.invalid> wrote:
> Chris Vine <chris@cvine--nospam--.freeserve.co.uk> wrote:
> > So what you are really proposing is a coding standard.
>
> No, it's not me who is proposing it.
>
> > The standard library doesn't guarantee that, so I think you are onto a
> > loser. It would also be unnecessarily inefficient. All that the C++
> > standard guarantees is that a const member function can safely be
> > called concurrently with another thread calling that or another const
> > member function on the same object, provided that no non-const member
> > function is called concurrently on the object. Otherwise "a locking
> > mechanism" (your words) is required when invoking the const member
> > functions (and any non-const member function).
>
> You proceeded to describe exactly what I was talking about.

This is ridiculous. I repeat that what you said was:

"Even beyond that, in the era of C++11 and newer, the constness of a
member function should indicate that it's thread-safe to call it
without a locking mechanism."

That is not what the C++ standard library provides. The best you have
been able to come up with is that in your opinion the standard library
"should" do so; but it doesn't and it never will.

> > In order to describe a function as "thread safe" you must be able to
> > call it safely in one thread irrespective of what another thread is
> > doing. What "thread safe" means is that you do not have to provide
> > external synchronisation.
>
> So now you start nitpicking about the exact terminology. Right.

No, you are wriggling. You have made an assertion about thread safety
which (unless you are talking about your own personal coding standards)
is wrong. In this business, labelling a function "thread-safe" means
that users do not need to provide external synchronisation to maintain
invariants, irrespective of what other threads are doing.

Daniel

unread,
Aug 26, 2018, 10:55:57 AM8/26/18
to
On Saturday, August 25, 2018 at 2:14:27 PM UTC-4, Chris Vine wrote:
>
> the C++ standard guarantees ... that a const member function can safely be
> called concurrently with another thread calling that or another const
> member function on the same object, provided that no non-const member
> function is called concurrently on the object.

For what definition of "safely"? In this context, as far as the the C++
standard is concerned, there is no distinction between calling unqualified f()
and f() const, as both can mutate state and have side effects.

Daniel

Chris Vine

unread,
Aug 26, 2018, 11:14:10 AM8/26/18
to
I was referring to the standard library - the text you have extracted
was preceded by the words "The standard library doesn't guarantee that,
so I think you are onto a loser. ...".

The C++ standard provides this guarantee for the standard library
somewhere, because I have read it. Are you asking me to look it up or
were you making a more general observation about other code? If the
latter I would agree with you: other code provides whatever guarantees
it chooses to offer.

Daniel

unread,
Aug 26, 2018, 11:31:36 AM8/26/18
to
On Sunday, August 26, 2018 at 11:14:10 AM UTC-4, Chris Vine wrote:

>
> The C++ standard provides this guarantee for the standard library
> somewhere, because I have read it.

Sorry, I misread your comment, that this statement was about the C++ standard
library, and not about the C++ standard generally.

Daniel

Juha Nieminen

unread,
Aug 27, 2018, 2:20:33 AM8/27/18
to
Chris Vine <chris@cvine--nospam--.freeserve.co.uk> wrote:
>> > The standard library doesn't guarantee that, so I think you are onto a
>> > loser. It would also be unnecessarily inefficient. All that the C++
>> > standard guarantees is that a const member function can safely be
>> > called concurrently with another thread calling that or another const
>> > member function on the same object, provided that no non-const member
>> > function is called concurrently on the object. Otherwise "a locking
>> > mechanism" (your words) is required when invoking the const member
>> > functions (and any non-const member function).
>>
>> You proceeded to describe exactly what I was talking about.
>
> This is ridiculous. I repeat that what you said was:
>
> "Even beyond that, in the era of C++11 and newer, the constness of a
> member function should indicate that it's thread-safe to call it
> without a locking mechanism."
>
> That is not what the C++ standard library provides.

Where exactly are you getting this "C++ standard library" from? Not from
my post at least. Nowhere did I made any mention whatsoever, not even
indirectly, about the C++ standard library.

Anyway, that doesn't matter, because *according to you* the C++ standard
library *does exactly* what I was talking about. Let me quote your own
post:

"All that the C++ standard guarantees is that a const member function
can safely be called concurrently with another thread calling that or
another const member function on the same object, provided that no
non-const member function is called concurrently on the object."

This is exactly what I was referring to. If you were confused by my
use of the term "thread-safe", then replace it with whatever other word
you want. However, don't cling onto whatever meaning you want to apply
to that term as if that had been what I meant, if I'm telling you what
I meant when I used it.

> No, you are wriggling. You have made an assertion about thread safety
> which (unless you are talking about your own personal coding standards)
> is wrong. In this business, labelling a function "thread-safe" means
> that users do not need to provide external synchronisation to maintain
> invariants, irrespective of what other threads are doing.

So you *are* nitpicking about the terminology.

Chris Vine

unread,
Aug 27, 2018, 6:09:25 AM8/27/18
to
Garbage.

"Even beyond that, in the era of C++11 and newer, the constness of a
member function should indicate that it's thread-safe to call it
without a locking mechanism."

Maybe you just expressed yourself poorly, maybe you don't understand
multi-threaded code. Since you are resolutely arguing the unarguable,
who knows.

Mistakes happen and this one is not the end of the world (unless you
are actually writing multi-threaded code for clients "without a locking
mechanism" for const methods operating on objects mutable by other
threads). Move on. And when you are in a hole, stop digging.

Juha Nieminen

unread,
Aug 27, 2018, 12:43:06 PM8/27/18
to
Chris Vine <chris@cvine--nospam--.freeserve.co.uk> wrote:
> Mistakes happen and this one is not the end of the world (unless you
> are actually writing multi-threaded code for clients "without a locking
> mechanism" for const methods operating on objects mutable by other
> threads). Move on. And when you are in a hole, stop digging.

So even after I clearly explain what I meant, you still choose to act
like an a-hole.

I explained in this thread, again and again, multiple times, that what
I mean is that "a const method should be implemented so that it can be
safely called from multiple threads without the need of a locking
mechanism". It's not even my idea.

Now you cling onto that term "thread-safe", apply your particular
meaning to it, rather than asking me what I meant, and declare yourself
victorious, and proceed to mock me.

You also conjured the C++ standard library from somewhere, even though
nowhere did I mention anything about it, and then you just ignore that.
Hilariously, you proceeded to explain that the C++ standard library
behaves *EXACTLY* like I described const member functions to be
supposed to behave. Yet, still, I am the one who is somehow in the wrong
here. Because of that one term "thread-safe" in one post, which you still
keep clinging onto.

woodb...@gmail.com

unread,
Aug 27, 2018, 1:00:25 PM8/27/18
to
On Monday, August 27, 2018 at 11:43:06 AM UTC-5, Juha Nieminen wrote:
>
> So even after I clearly explain what I meant, you still choose to act
> like an a-hole.
>
> I explained in this thread, again and again, multiple times, that what
> I mean is that "a const method should be implemented so that it can be
> safely called from multiple threads without the need of a locking
> mechanism". It's not even my idea.
>
> Now you cling onto that term "thread-safe", apply your particular
> meaning to it, rather than asking me what I meant, and declare yourself
> victorious, and proceed to mock me.
>
> You also conjured the C++ standard library from somewhere, even though
> nowhere did I mention anything about it, and then you just ignore that.
> Hilariously, you proceeded to explain that the C++ standard library
> behaves *EXACTLY* like I described const member functions to be
> supposed to behave. Yet, still, I am the one who is somehow in the wrong
> here. Because of that one term "thread-safe" in one post, which you still
> keep clinging onto.


There's no shortage of "intelligent, but" people here like Chris.
The best thing I can say about them is they are intelligent. I've
called them "little vultures" before -- they wait for someone to
trip and then try to pounce on them. Little vultures == gnats.


Brian
Ebenezer Enterprises - "If a good man falls seven times, he gets back up.
But when trouble strikes the wicked, that's the end of them." Proverbs 24:16

http://webEbenezer.net

Chris Vine

unread,
Aug 27, 2018, 3:26:12 PM8/27/18
to
On Mon, 27 Aug 2018 16:42:52 -0000 (UTC)
Juha Nieminen <nos...@thanks.invalid> wrote:
> Chris Vine <chris@cvine--nospam--.freeserve.co.uk> wrote:
> > Mistakes happen and this one is not the end of the world (unless you
> > are actually writing multi-threaded code for clients "without a locking
> > mechanism" for const methods operating on objects mutable by other
> > threads). Move on. And when you are in a hole, stop digging.
>
> So even after I clearly explain what I meant, you still choose to act
> like an a-hole.
>
> I explained in this thread, again and again, multiple times, that what
> I mean is that "a const method should be implemented so that it can be
> safely called from multiple threads without the need of a locking
> mechanism". It's not even my idea.

I would not agree with that point either. Const methods should, in my
opinion, be implemented so that they can safely be called from multiple
threads without the need for a locking mechanism provided that the
object concerned cannot also be concurrently mutated by a non-const
method. If it can be concurrently mutated the user needs an external
locking mechanism. It also happens to the be approach adopted by most
code I have seen, including the standard library.

> Now you cling onto that term "thread-safe", apply your particular
> meaning to it, rather than asking me what I meant, and declare yourself
> victorious, and proceed to mock me.
>
> You also conjured the C++ standard library from somewhere, even though
> nowhere did I mention anything about it, and then you just ignore that.
> Hilariously, you proceeded to explain that the C++ standard library
> behaves *EXACTLY* like I described const member functions to be
> supposed to behave. Yet, still, I am the one who is somehow in the wrong
> here. Because of that one term "thread-safe" in one post, which you still
> keep clinging onto.

I am not trying to mock you. I was trying to point out, apparently
unsuccessfully, that if you think that invoking a const method is going
to be thread-safe by virtue of it being const, you will be writing
thread-unsafe code. I think you are so self-defensive that you have
become confused.

As to the meaning of "thread-safe", (i) it is well established in the
industry, and (ii) words cannot just mean whatever you want them to
mean.

Humpty Dumpty: "... There's glory for you!"

"I don’t know what you mean by 'glory'," Alice said.

Humpty Dumpty smiled contemptuously. "Of course you don't – till I
tell you. I meant 'there's a nice knock-down argument for you!'"

"But 'glory' doesn't mean 'a nice knock-down argument'," Alice
objected.

"When I use a word," Humpty Dumpty said, in a rather scornful tone,
"it means just what I choose it to mean – neither more nor less."

"The question is," said Alice, "whether you can make words mean so
many different things."

"The question is," said Humpty Dumpty, "which is to be master - that's
all."

I am with Alice, not Humpty Dumpty.

Vir Campestris

unread,
Aug 27, 2018, 5:53:30 PM8/27/18
to
On 27/08/2018 17:42, Juha Nieminen wrote:
> I explained in this thread, again and again, multiple times, that what
> I mean is that "a const method should be implemented so that it can be
> safely called from multiple threads without the need of a locking
> mechanism". It's not even my idea.

I've read all through this thread.

Can I make a general appeal here to everyone to not drop to insults? It
doesn't help.

That aside, the view I've always taken for a const method is "it won't
alter the visible state of the object".

I can imagine a method that makes a summary of the state of the object.
Suppose, for example, the collection can be boiled down to a string. The
to_str() method would collate whatever data was needed to represent the
object. That might involve significant calculations, and might be enough
that it's worth caching the string internally.

If calling the method from two threads simultaneously is permitted then
the method will have to take a lock on the cache before operating.

If the method will only ever be run in a single-threaded context then
there is no need for the lock, and it is unnecessary overhead.

It may be that in your application the use of threads is so widespread
that it is worth having a coding standard that states that all const
methods must be able to run concurrently with all other const methods,
and that this makes the maintenance of your codebase easier. In fact, it
probably does (and the codebase I am working on now might benefit from
such a standard!)

BUT

It's not something that is needed everywhere. Specifically it is not
needed for single threaded applications, and will only add complexity.
Which means potential bugs.

So I don't support your idea that _all_ const methods should be thread safe.

Andy

Chris Vine

unread,
Aug 27, 2018, 6:19:35 PM8/27/18
to
On Mon, 27 Aug 2018 22:53:17 +0100
Vir Campestris <vir.cam...@invalid.invalid> wrote:
> It may be that in your application the use of threads is so widespread
> that it is worth having a coding standard that states that all const
> methods must be able to run concurrently with all other const methods,
> and that this makes the maintenance of your codebase easier. In fact, it
> probably does (and the codebase I am working on now might benefit from
> such a standard!)

I do aim for that standard in my code. I don't think it causes much
overhead. Generally it just requires locking of any member data marked
'mutable' and, so far as relevant, any static data, and synchronization
of any i/o done by const methods. That is normally about it.

The C++ standard library adopts this approach.

> .. I don't support your idea that _all_ const methods should be thread safe.

I am strongly against that. That would cause unacceptable overhead in
my view. It would require locking of all member or static data read by
the const methods which might be mutated by non-const methods. To make
all const methods thread-safe you practically have to make all non-const
methods thread safe as well.

I think that it is better to leave such cases to external
synchronization by the user. That is also the approach adopted by the
standard library, except where otherwise stated. (Obviously things like
mutexes have to be thread-safe.)

Chris

Chris M. Thomasson

unread,
Aug 27, 2018, 6:25:07 PM8/27/18
to
On 8/27/2018 9:42 AM, Juha Nieminen wrote:
> Chris Vine <chris@cvine--nospam--.freeserve.co.uk> wrote:
>> Mistakes happen and this one is not the end of the world (unless you
>> are actually writing multi-threaded code for clients "without a locking
>> mechanism" for const methods operating on objects mutable by other
>> threads). Move on. And when you are in a hole, stop digging.
>
> So even after I clearly explain what I meant, you still choose to act
> like an a-hole.
>
> I explained in this thread, again and again, multiple times, that what
> I mean is that "a const method should be implemented so that it can be
> safely called from multiple threads without the need of a locking
> mechanism". It's not even my idea.

What about const functions that are only called from a single thread?
Say the const function is on a per-thread data structure. Why would the
function need any synchronization if it only operates on data that is
totally owned by the only thread that will ever call it?
________________________
class per_thread
{
int foo;

public:
per_thread(int foo_) : foo(foo_) {}

public:
int get() const
{
return foo + 21;
}
};
________________________

There is no need to make per_thread::foo an atomic type.

Chris Vine

unread,
Aug 27, 2018, 8:40:13 PM8/27/18
to
On Mon, 27 Aug 2018 20:25:35 +0100
Chris Vine <chris@cvine--nospam--.freeserve.co.uk> wrote:
> On Mon, 27 Aug 2018 16:42:52 -0000 (UTC)
> Juha Nieminen <nos...@thanks.invalid> wrote:
> > Chris Vine <chris@cvine--nospam--.freeserve.co.uk> wrote:
> > > Mistakes happen and this one is not the end of the world (unless you
> > > are actually writing multi-threaded code for clients "without a locking
> > > mechanism" for const methods operating on objects mutable by other
> > > threads). Move on. And when you are in a hole, stop digging.
> >
> > So even after I clearly explain what I meant, you still choose to act
> > like an a-hole.
> >
> > I explained in this thread, again and again, multiple times, that what
> > I mean is that "a const method should be implemented so that it can be
> > safely called from multiple threads without the need of a locking
> > mechanism". It's not even my idea.
>
> I would not agree with that point either. Const methods should, in my
> opinion, be implemented so that they can safely be called from multiple
> threads without the need for a locking mechanism provided that the
> object concerned cannot also be concurrently mutated by a non-const
> method. If it can be concurrently mutated the user needs an external
> locking mechanism. It also happens to the be approach adopted by most
> code I have seen, including the standard library.

OK, I have now reread the entire thread twice to see where the
disagreement is coming from. Piecing it together, I think you agree
with what I have just said. The problem is that you expressed
yourself, in your reference to thread safety, more expansively than
perhaps you intended, and I took your words at face value.

So let's agree on the above formulation. Let us agree to disagree on
what it means for a function to be "thread safe", since it isn't
material to the formulation that we can agree on. (I can carry on with
"thread safe" if you wish to, but I suggest better not to.)

Juha Nieminen

unread,
Aug 28, 2018, 2:16:49 AM8/28/18
to
Chris Vine <chris@cvine--nospam--.freeserve.co.uk> wrote:
> So let's agree on the above formulation. Let us agree to disagree on
> what it means for a function to be "thread safe", since it isn't
> material to the formulation that we can agree on. (I can carry on with
> "thread safe" if you wish to, but I suggest better not to.)

I don't think it should be so controversial that the sentence "it's
thread-safe to call this member function" implies, without the need
for long explanations, that multiple threads can call *that particular
function* at the same time without having to worry about concurrency issues.

If you object to the word "thread-safe" being used for this purpose,
then what other word would you use?

I suppose that if one would want to be absolute clear about the meaning,
one could add "(as long as no non-const functions of this object are
being called at the same time)" or something to that effect.

Juha Nieminen

unread,
Aug 28, 2018, 2:20:42 AM8/28/18
to
Chris M. Thomasson <invalid_chr...@invalid.invalid> wrote:
>> I explained in this thread, again and again, multiple times, that what
>> I mean is that "a const method should be implemented so that it can be
>> safely called from multiple threads without the need of a locking
>> mechanism". It's not even my idea.
>
> What about const functions that are only called from a single thread?
> Say the const function is on a per-thread data structure. Why would the
> function need any synchronization if it only operates on data that is
> totally owned by the only thread that will ever call it?

I don't understand what you are asking.

If a const function is safe to call from multiple threads, it's certainly
safe to call from one single thread.

(And let me clarify once again that what I mean is that it's safe for
multiple threads to call *that particular function*. It does not mean
that if some thread *also* calls some other non-const function, it's
still safe. In practice this means that const methods shouldn't be
modifying anything. Or even if for some reason they have to, that
modification should be atomic or use a locking mechanism.)

Chris M. Thomasson

unread,
Aug 28, 2018, 2:31:24 AM8/28/18
to
On 8/27/2018 11:20 PM, Juha Nieminen wrote:
> Chris M. Thomasson <invalid_chr...@invalid.invalid> wrote:
>>> I explained in this thread, again and again, multiple times, that what
>>> I mean is that "a const method should be implemented so that it can be
>>> safely called from multiple threads without the need of a locking
>>> mechanism". It's not even my idea.
>>
>> What about const functions that are only called from a single thread?
>> Say the const function is on a per-thread data structure. Why would the
>> function need any synchronization if it only operates on data that is
>> totally owned by the only thread that will ever call it?
>
> I don't understand what you are asking.

Not all const needs to be thread safe?

Chris Vine

unread,
Aug 28, 2018, 4:59:34 AM8/28/18
to
On Tue, 28 Aug 2018 06:16:33 -0000 (UTC)
Juha Nieminen <nos...@thanks.invalid> wrote:
> Chris Vine <chris@cvine--nospam--.freeserve.co.uk> wrote:
> > So let's agree on the above formulation. Let us agree to disagree on
> > what it means for a function to be "thread safe", since it isn't
> > material to the formulation that we can agree on. (I can carry on with
> > "thread safe" if you wish to, but I suggest better not to.)
>
> I don't think it should be so controversial that the sentence "it's
> thread-safe to call this member function" implies, without the need
> for long explanations, that multiple threads can call *that particular
> function* at the same time without having to worry about concurrency issues.
>
> If you object to the word "thread-safe" being used for this purpose,
> then what other word would you use?

I do object to it being used for that purpose. std::string::length() is
const and meets your description. I doubt anyone would describe it as
"thread-safe", because if another thread were to append or delete a
character without external synchronization you would have undefined
behaviour[1].

I don't think there is an expression which is generally used to meet
your description. "const in a standard library sense" might do, but
that would require the hearer to know what the C++ standard prescribes
for the standard library on this point.

> I suppose that if one would want to be absolute clear about the meaning,
> one could add "(as long as no non-const functions of this object are
> being called at the same time)" or something to that effect.

That would do, although in the absence of synchronization "at the same
time" is somewhat problematic. Different threads can have different
views about state and time.

[1] The standard says you have undefined behaviour. In fact on many
platforms the code would work, albeit return values might be somewhat
out of date as if by relaxed memory ordering, because the fundamental
type of which std::size_t is a typedef is generally atomic at the
hardware level. If it helps the point, visualize a more complex const
method which might crash your program.

Chris Vine

unread,
Aug 28, 2018, 5:10:36 AM8/28/18
to
On Tue, 28 Aug 2018 09:59:15 +0100
Chris Vine <chris@cvine--nospam--.freeserve.co.uk> wrote:
> [1] The standard says you have undefined behaviour. In fact on many
> platforms the code would work, albeit return values might be somewhat
> out of date as if by relaxed memory ordering, because the fundamental
> type of which std::size_t is a typedef is generally atomic at the
> hardware level. If it helps the point, visualize a more complex const
> method which might crash your program.

I qualify that. std::string::length() wouldn't crash, but it would only
"work" without synchronization in many std::string implementations if
only one thread were to append or delete a character without
synchronization. If two or more could do so without external
synchronization the length counter (and the string) could get in an
inconsistent state which would breach invariants.

Daniel

unread,
Aug 28, 2018, 11:31:51 AM8/28/18
to
On Tuesday, August 28, 2018 at 4:59:34 AM UTC-4, Chris Vine wrote:
> On Tue, 28 Aug 2018 06:16:33 -0000 (UTC)
> Juha Nieminen <nos...@thanks.invalid> wrote:

> > I don't think it should be so controversial that the sentence "it's
> > thread-safe to call this member function" implies, without the need
> > for long explanations, that multiple threads can call *that particular
> > function* at the same time without having to worry about concurrency issues.
> >
> > If you object to the word "thread-safe" being used for this purpose,
> > then what other word would you use?
>
> I don't think there is an expression which is generally used to meet
> your description.

How about "reentrant"?

Daniel

Öö Tiib

unread,
Aug 28, 2018, 11:42:38 AM8/28/18
to
On Tuesday, 28 August 2018 09:16:49 UTC+3, Juha Nieminen wrote:
>
> I don't think it should be so controversial that the sentence "it's
> thread-safe to call this member function" implies, without the need
> for long explanations, that multiple threads can call *that particular
> function* at the same time without having to worry about concurrency issues.
>
> If you object to the word "thread-safe" being used for this purpose,
> then what other word would you use?

May be "reentrant"?

Chris Vine

unread,
Aug 28, 2018, 3:26:23 PM8/28/18
to
I would need to think about it, but I think it is possible to have a
non-reentrant member function which still meets the standard library
demands for const member functions under discussion (below, "the const
requirements"), or a reentrant member function which does not meet the
const requirements.

The rules on accessing and modifying non-local data such as member
variables would be different between the two. In a reentrant member
function suitable for use as a signal handler such member variables
would have to be of type sig_atomic_t and qualified as volatile. Under
the const requirements they would have to be marked mutable and
be atomic or protected by locking, or be thread local.
0 new messages