Thursday, October 21, 2021

Digest for comp.lang.c++@googlegroups.com - 25 updates in 3 topics

Juha Nieminen <nospam@thanks.invalid>: Oct 21 05:23AM

Time and again I see beginner C++ programmers make the same mistake:
Make functions take objects by non-const reference, even when (in the
vast, vast majority of cases) the function doesn't modify those objects.
 
In one particularly egregious case some beginner programmer had written
a comparator lambda that took two std::string objects by reference,
wondered why he was getting a compiler error, and then removed the
references, so it was taking the objects by value. That way it compiled.
Then he wondered why it was so slow.
 
I think it was a mistake to make references non-const by default.
It's logical (and consistent with pointer syntax) of course, but I think
it was a mistake. In the vast, vast majority of cases if you create a
reference to something else, you want it to be const (and there are
many good reasons why it should be const). It's extremely rare to
explicitly want a non-const reference.
 
And the thing is, C++98 has a *perfect* keyword to explicitly denote
that you want a non-const reference, which could have been used for
this purpose, so no new keyword would be needed for this: 'mutable'.
 
In other words, I think C++ would have been better if it worked like
this:
 
void foo1(std::string& str)
{
str = "hello"; // error: 'str' is const
}
 
void foo2(mutable std::string& str)
{
str = "hello"; // ok
}
 
(You could still write "const std::string&", but it would just have
the exact same meaning as "std::string&", ie. in this case the
'const' is superfluous, a bit like how 'signed' is superfluous
in "signed int".)
David Brown <david.brown@hesbynett.no>: Oct 21 08:54AM +0200

On 21/10/2021 07:23, Juha Nieminen wrote:
> the exact same meaning as "std::string&", ie. in this case the
> 'const' is superfluous, a bit like how 'signed' is superfluous
> in "signed int".)
 
I agree with you entirely. But if we are going for wishful thinking
about how C++ could have been made better, I'd have preferred "const"
for all variables and required "mutable" to declare a variable that
could be modified. (Of course that would mean you'd need something else
for class members that are today "mutable". But I think it's a lot more
common for people to make variables that could have been "const" but
aren't, than to use mutable members.)
RacingRabbit@watershipdown.co.uk: Oct 21 09:12AM

On Thu, 21 Oct 2021 05:23:03 -0000 (UTC)
>the exact same meaning as "std::string&", ie. in this case the
>'const' is superfluous, a bit like how 'signed' is superfluous
>in "signed int".)
 
Looking for logic in C++ keywords is a hiding to nothing. Eg const_cast
actually means remove const'ness , not add it which is frankly bizarre.
You might as well have true mean false and false mean true. Similarly
putting throw() at the end of a function def means it can't throw! Though at
least that insanity has been superceeded by noexcept now.
Paavo Helde <myfirstname@osa.pri.ee>: Oct 21 12:18PM +0300

21.10.2021 08:23 Juha Nieminen kirjutas:
 
> I think it was a mistake to make references non-const by default.
> It's logical (and consistent with pointer syntax) of course, but I think
> it was a mistake.
Agreed.
 
By default in C is to pass objects by value, so the changes in the
object will not affect the caller side. On the caller side the pass by
value and pass by reference look the same, so this important feature (no
surprises on the caller side) was lost in C++. Using a const reference
fixes this loss, so one can even argue that using a const reference, at
least by default would also be logical and consistent, in some sense.
 
If it were up to me, I would have required extra syntax on the caller
side to pass via non-const reference, like @var.
 
Pushing everything more const would mean the language would behave and
feel more "functional" and less "OOP", but that's a good thing.
Juha Nieminen <nospam@thanks.invalid>: Oct 21 09:48AM

> for class members that are today "mutable". But I think it's a lot more
> common for people to make variables that could have been "const" but
> aren't, than to use mutable members.)
 
That would quite quickly turn quite annoying, eg. with things like
for-loops:
 
for(int i = 0; i < 10; ++i) // error, i is const
Juha Nieminen <nospam@thanks.invalid>: Oct 21 09:52AM

> Looking for logic in C++ keywords is a hiding to nothing. Eg const_cast
> actually means remove const'ness , not add it which is frankly bizarre.
 
What would have been a better name for that keyword in your opinion?
 
> Similarly
> putting throw() at the end of a function def means it can't throw! Though at
> least that insanity has been superceeded by noexcept now.
 
I think it's pretty logical. It just lists all the exceptions that the
function can throw. If the list is empty, it means it doesn't throw
any exception.
 
If they wanted to be clearer, it should have been "throws(whatever)", but
that would have required adding yet another single-use keyword.
Paavo Helde <myfirstname@osa.pri.ee>: Oct 21 12:55PM +0300

21.10.2021 12:48 Juha Nieminen kirjutas:
 
> That would quite quickly turn quite annoying, eg. with things like
> for-loops:
 
> for(int i = 0; i < 10; ++i) // error, i is const
 
Solved by C++20:
 
for (int i : std::ranges::iota(0, 10))
 
Having const default would mean additional bonus in that 'i' would be
const inside the loop body.
RacingRabbit@watershipdown.co.uk: Oct 21 10:36AM

On Thu, 21 Oct 2021 09:52:53 -0000 (UTC)
>> Looking for logic in C++ keywords is a hiding to nothing. Eg const_cast
>> actually means remove const'ness , not add it which is frankly bizarre.
 
>What would have been a better name for that keyword in your opinion?
 
unconst_cast , noconst_cast, take your pick.
 
 
>I think it's pretty logical. It just lists all the exceptions that the
>function can throw. If the list is empty, it means it doesn't throw
>any exception.
 
Except throw inside a function means throw any exception currently on the stack.
You can't have it both ways and for once the C++ committee saw sense and
replaced it with noexcept.
 
>If they wanted to be clearer, it should have been "throws(whatever)", but
>that would have required adding yet another single-use keyword.
 
There's nothing wrong with single use keywords if they make things clearer.
This should have been done with the = 0 in pure virtuals and the spurious int
in postfix operator definitions.
 
eg:
virtual void myfunc() = 0; -> pure virtual void myfunc();
myclass &operator++(int) -> myclass &operator++() postfix
David Brown <david.brown@hesbynett.no>: Oct 21 12:57PM +0200

On 21/10/2021 11:48, Juha Nieminen wrote:
 
> That would quite quickly turn quite annoying, eg. with things like
> for-loops:
 
> for(int i = 0; i < 10; ++i) // error, i is const
 
for (mutable int i = 0; i < 10; ++i)
 
Yes, there are many places where you want variable variables - but I
think overall you typically have more that could be declared const than
have to be variable. (The idea is not without precedence - there are
other modern languages with constant objects by default.)
 
For loops, I think the best solution would be a mixture - the loop
variable should be mutable within the controlling expressions, but
should be constant within the statement or block - as though you had
written:
 
for (int i = 0; i < 10; i++) {
const auto i_ = i;
const auto i = i_;
 
// Here, "i" is constant
}
Bonita Montero <Bonita.Montero@gmail.com>: Oct 21 01:13PM +0200

You're compulsive.
"Alf P. Steinbach" <alf.p.steinbach@gmail.com>: Oct 21 01:22PM +0200

On 21 Oct 2021 07:23, Juha Nieminen wrote:
> reference to something else, you want it to be const (and there are
> many good reasons why it should be const). It's extremely rare to
> explicitly want a non-const reference.
 
Agreed. So what can you do about it?
 
Just define
 
template< class T > using Ref_ = const T&;
 
And then write
 
void foo( Ref_<Baluba> x )
 
instead of
 
void foo( const Baluba& x )
 
A more clever definition in terms of a nested type of a class template,
like the standard library usually does, does not support type deduction
for function templates, but the above supports e.g.
 
template< class T >
void foo( Ref_<T> x )
 
with calls like `foo( something )`.
 
When the same approach is adopted for pointers it supports general
left/west `const`.
 
The one big drawback of this approach is that code using such
definitions can't be posted to this group without Mr. Fibble complaining
loudly and posting offensive remarks about how it's impossible to grok.
 
 
> the exact same meaning as "std::string&", ie. in this case the
> 'const' is superfluous, a bit like how 'signed' is superfluous
> in "signed int".)
 
- Alf
Manfred <noname@add.invalid>: Oct 21 01:57PM +0200

On 10/21/2021 7:23 AM, Juha Nieminen wrote:
> the exact same meaning as "std::string&", ie. in this case the
> 'const' is superfluous, a bit like how 'signed' is superfluous
> in "signed int".)
 
Good point. However, I value syntax consistency a lot, so given the
current state of things (non-const default pointers) I think non-const
default references are preferable to me - and I write /many/ more 'const
T&' declarations than 'T&' myself.
In an ideal world, if we were able to have const default pointers as
well, then I would endorse your view entirely.
 
BTW Alf's alternative has its appeal.
Bo Persson <bo@bo-persson.se>: Oct 21 03:08PM +0200

On 2021-10-21 at 13:13, Bonita Montero wrote:
> You're compulsive.
 
Who, me?
RacingRabbit@watershipdown.co.uk: Oct 21 01:40PM

On Thu, 21 Oct 2021 12:57:05 +0200
>variable should be mutable within the controlling expressions, but
>should be constant within the statement or block - as though you had
>written:
 
I think const is a lot of fuss about nothing frankly. I barely use them
anyway and I can't remember the last time that I had a bug due to updating
a variable that shouldn't have been updated. For those who think its simply
an indication to other devs that a variable won't be changed then fair enough
but personally I find a lot of const/non const compilation errors related
to functions a PITA.
Bart <bc@freeuk.com>: Oct 21 03:04PM +0100

> an indication to other devs that a variable won't be changed then fair enough
> but personally I find a lot of const/non const compilation errors related
> to functions a PITA.
 
I don't about C++, but in C, you can take a program, remove all the
'const' qualifiers, and it will still compile and work.
 
Makes you think...
Manfred <noname@add.invalid>: Oct 21 04:41PM +0200

On 10/21/2021 4:04 PM, Bart wrote:
 
> I don't about C++, but in C, you can take a program, remove all the
> 'const' qualifiers, and it will still compile and work.
 
> Makes you think...
 
...mumble, obviously 'const' is almost exclusively for the programmer's
convenience (some implementations may use it to map some const data to
read only memory, but that's probably a minor use compared to the
massive benefit in accurate modeling of a process).
 
The categories of immutable and mutable data are pretty relevant in
process modeling, and since SW design is a lot about modeling, long live
'const'.
RacingRabbit@watershipdown.co.uk: Oct 21 02:51PM

On Thu, 21 Oct 2021 15:04:19 +0100
 
>I don't about C++, but in C, you can take a program, remove all the
>'const' qualifiers, and it will still compile and work.
 
>Makes you think...
 
Well quite. But then I started out in C and const wasn't a thing so you had
to know what was going on and not always rely on the compiler to tell you.
But then C doesn't have references I suppose and its a bit difficult to
accidentaly dereference a pointer and update it unlike a C++ reference. Even
so, I still don't like consts. But its just personal taste.
RacingRabbit@watershipdown.co.uk: Oct 21 02:57PM

On Thu, 21 Oct 2021 16:41:34 +0200
 
>The categories of immutable and mutable data are pretty relevant in
>process modeling, and since SW design is a lot about modeling, long live
>'const'.
 
Tbh if you don't know which data should be left alone and which you can update
you probably shouldn't be working on the code until you learn it a bit better.
As for private/protected variables in library classes, that just pisses me off.
If I want to alter something then let me Mr Library Coder. Its not up to you
to decide what I can and can't alter in my own program and you're not going to
be able to think up every possible use case in which your "private" variable
might need to be accessed or changed.
 
I actually had this issue with an in house lib at a company but the muppet
who wrote it refused to make the variable public or even available via a
setter even though we needed to access it. In the end I got the address
of a public variable in the class, counted back in memory and dereferenced the
pointer where his private var was stored. Worked a treat though very fragile.
Eventually management made him add a getter function so that hack was removed.
James Kuyper <jameskuyper@alumni.caltech.edu>: Oct 21 12:07PM -0400

On 10/21/21 5:12 AM, RacingRabbit@watershipdown.co.uk wrote:
...
> Looking for logic in C++ keywords is a hiding to nothing. Eg const_cast
> actually means remove const'ness , not add it which is frankly bizarre.
 
You can use const_cast<> to add const as easily as removing it. Doing so
is normally unnecessary, because such conversions can be done
implicitly, which might be what gave you that impression.
 
You can also add and remove the other qualifier, volatile. Therefore, I
think qual_cast<> might have been a better name for it.
James Kuyper <jameskuyper@alumni.caltech.edu>: Oct 21 12:09PM -0400

On Thu, 21 Oct 2021 15:04:19 +0100
Bart <bc@freeuk.com> wrote:
...
>I don't about C++, but in C, you can take a program, remove all the
>'const' qualifiers, and it will still compile and work.
 
>Makes you think...
 
Keep in mind that this is strictly true in C only if you remove all the
"const" qualifiers from all of the #included header files, and you can't
do that with standard library headers. It would also be difficult to do
with the headers associated with third-party libraries.
 
More importantly, that's true only if the program would compile without
diagnostics before the removal of the 'const' qualifiers, and there's a
simple, blindingly obvious reason for that, which does NOT count as an
argument against the proper use of "const":
 
The declaration of an identifier containing the 'const' keyword
indicates that this identifier should not be used in any way that puts
the object qualified by that keyword in danger of being modified. The
purpose of that keyword is to enable diagnostic messages when the
identifier is used in an expression that could put that object in danger
of being modified. If your program generates no diagnostics, that means
that it contains no such expressions. Removing "const" from the entire
translation unit, including #included headers, will not change the fact
that there is no danger, and the program should therefore work just the
same as before. However, if you modify the program again after removing
all "const" keywords, that modification might create such a danger, but
the implementation no longer has any obligation of warning you about the
danger.
 
You said that you don't know about C++. Well there's an important
difference between C++ and C in this regard: function overloading. A
function can be overloaded based upon the difference in the way one or
more of its arguments is qualified. The overloads may do significantly
different things - if so, the non-const overload usually attempts to
modify the relevant object, whereas the const overload uses some
work-around to avoid the need to modify it. That work-around is usually
inconvenient in some way, otherwise there would have been no need to
declare the const overload. Therefore, at best, removing all use of the
"const" keyword would require that the non-const overload be dropped,
and that the less convenient const overload be used at all times.
 
That's "usually". Overloads are entirely under the programmer's control,
and the difference between them need not be "usual" - it very often
isn't. It would be trivial to create overloads that do significantly
different things with const and non-const arguments (most trivially,
they could print out "const" and "non-const" respectively). No single
function can replace both overloads, but it would have to do so if you
removed all occurances of the "const" keyword.
Branimir Maksimovic <branimir.maksimovic@icloud.com>: Oct 21 09:27PM

> the exact same meaning as "std::string&", ie. in this case the
> 'const' is superfluous, a bit like how 'signed' is superfluous
> in "signed int".)
Good thinking, but now to late, perhaps with -std=c++22
and latter on?
 
--
 
7-77-777
Evil Sinner!
with software, you repeat same experiment, expecting different results...
Bart <bc@freeuk.com>: Oct 21 11:49PM +0100

On 21/10/2021 17:09, James Kuyper wrote:
> declare the const overload. Therefore, at best, removing all use of the
> "const" keyword would require that the non-const overload be dropped,
> and that the less convenient const overload be used at all times.
 
Actually here's an example from C where const changes the behaviour:
 
#include <stdio.h>
#include <stdint.h>
 
int main(void) {
#define issigned(x) _Generic((x),\
int8_t: "S",\
int16_t: "S",\
int32_t: "S",\
const int32_t: "const S",\
int64_t: "S",\
uint8_t: "u",\
uint16_t: "u",\
uint32_t: "u",\
uint64_t: "u",\
default: "other")
 
int32_t x;
// const int32_t x;
puts(issigned(x));
}
 
The output is different when x has a const attribute.
"james...@alumni.caltech.edu" <jameskuyper@alumni.caltech.edu>: Oct 21 04:21PM -0700

On Thursday, October 21, 2021 at 6:49:29 PM UTC-4, Bart wrote:
> > "const" qualifiers from all of the #included header files, and you can't
> > do that with standard library headers. It would also be difficult to do
> > with the headers associated with third-party libraries.
...
> puts(issigned(x));
> }
 
> The output is different when x has a const attribute.
 
You're correct, I forgot about that. _Generic provides a capability similar to but much more restricted than function overloading, and as such allows the behavior to depend upon the qualifiers.
Manfred <noname@add.invalid>: Oct 21 04:55PM +0200

On 10/21/2021 3:07 PM, rabbit rabbit wrote:
> -The latest book I have read is 《C++ primer》,but it only talks about some features of C++11. I would like to know if there are any good books or videos that can help me learn the latest C++ features.
 
> * Do I need to change my reading books?
> - The three books I am currently reading are 《Effective c++》,《More Effective C++》and 《The Annotated STL Sources》,After reading for a while, I found that these three books are too old, some of the C++ features mentioned in them are out of date, should I continue reading or find some new books. If I should find new books, then do you have any recommendations for books?
 
That is one decent list:
 
https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list
rabbit rabbit <1604456428@qq.com>: Oct 21 06:07AM -0700

I know this place from the book 《More Effective C++》.I heard from that book that there are many c++ experts here and I would like to ask for help on the following questions .Sincere thanks everyone .* is followed by the name of the question and - is followed by some details
 
* Where is the best c++ forum in the world right now
- The two places(comp.lang.c++.moderated,comp.std.c++) mentioned in that book have been unattended for a long time, and the most recent reply is in 2016. emmmmmm, I know my information is a bit outdated,so that is reason why i am asking this foolish question. Is it right here or on StackOverflow or somewhere else?
 
* Where can I learn about the latest features of C++14/17/20?
-The latest book I have read is 《C++ primer》,but it only talks about some features of C++11. I would like to know if there are any good books or videos that can help me learn the latest C++ features.
 
* Do I need to change my reading books?
- The three books I am currently reading are 《Effective c++》,《More Effective C++》and 《The Annotated STL Sources》,After reading for a while, I found that these three books are too old, some of the C++ features mentioned in them are out of date, should I continue reading or find some new books. If I should find new books, then do you have any recommendations for books?
You received this digest because you're subscribed to updates for this group. You can change your settings on the group membership page.
To unsubscribe from this group and stop receiving emails from it send an email to comp.lang.c+++unsubscribe@googlegroups.com.

No comments: