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

Why should a "c" programmer learn c++ ?

156 views
Skip to first unread message

olcott

unread,
Sep 9, 2020, 12:45:34 PM9/9/20
to
For all "c" programmers to get the maximum benfit from c++ with the
least learning curve cost you only need to learn three things about c++
(1) C++ classes
(2) std::vector
(3) std::string

I spoke with someone on the comp.lang.c recently about the benefits of
c++. Her objections was that c++ has a huge learning curve.

I have been a "c" programmer since K&R was the official standard and
only learned those very few things about c++ that make programming much
easier. In two decades as a c++ programmer I don't hardly use anything
else besides those three things.

I learned about c++ classes, std::vector and std::string, that is the
tiny subset of c++ that makes "c" programming much easier. I have
continued to use the stdio.h I/O library of "c" in all my c++ programs.
I just started calling this library <cstdio> by its c++ name.

C++ classes implement the key most important and useful aspect of Object
Oriented Programming (OOP). I have never found any other aspect of OOP
useful.

C++ classes are just "c" structs having their own member functions that
operate only on this data. Code and data can be kept together in the
same place eliminating the possibility of data dependency side-effects.
With OOP you can create self-contained units of modularity. This is ht e
greatest thing about c++ and OOP.

With std::vector you can have an array of anything that totally handles
all of its own memory management that can be kept in a tiny little
pointer in a stack (local) variable. You can use normal "c" substripts
to access elements.

The array always knows its current size: size() and you can append
another element with memory management automatically handled for you
with push_back(). The allocation algorithm is an optimal balance between
time and space can be easily superseded with resize() or reserve().

std::string is a string of characters that can grow as large as needed
and has the same interface as std::vector. The above three things is all
the c++ that "c" programmer ever needs to know.

--
Copyright 2020 Pete Olcott

Bonita Montero

unread,
Sep 9, 2020, 12:54:58 PM9/9/20
to
> The array always knows its current size: size() and you can append
> another element with memory management automatically handled for you
> with push_back(). The allocation algorithm is an optimal balance between
> time and space can be easily superseded with resize() or reserve().

If you're talking about std::array - its size can't be changed.

olcott

unread,
Sep 9, 2020, 1:07:21 PM9/9/20
to
I am referring back to std::vector as a type of array, I am using terms
that "c" programmers know and mapping these terms to the most useful c++
equivalent.

James Kuyper

unread,
Sep 9, 2020, 1:09:01 PM9/9/20
to
On Wednesday, September 9, 2020 at 12:54:58 PM UTC-4, Bonita Montero wrote:

[missing attribution restored:]
The paragraph you quoted was immediately preceded by this one:

> > With std::vector you can have an array of anything that totally handles
> > all of its own memory management that can be kept in a tiny little
> > pointer in a stack (local) variable. You can use normal "c" substripts
> > to access elements.

Which makes it quite clear that the array he was talking about in the
paragraph you quoted is the array managed by std::vector, which has a
size that quite definitely can change. Note, in particular, that he's
fairly careful about prefixing standard library identifiers with
"std::", so it was clear that the array he was talking about was not
std::array<>. Other clues that this is the case are his mentions of
push_back(), resize(), and reserve(), none of which are members of
std::array<>, but they are members of std::vector<>.

olcott

unread,
Sep 9, 2020, 1:26:50 PM9/9/20
to
It was a good idea to make it even clearer though so I updated it.
The std::vector array always knows its current size...

Keith Thompson

unread,
Sep 9, 2020, 1:46:57 PM9/9/20
to
olcott <No...@NoWhere.com> writes:
[...]
> It was a good idea to make it even clearer though so I updated it.
> The std::vector array always knows its current size...

You can't really update a Usenet post. What you did was post a
new version of it, with no visible indication of what had changed.
If you want to clarify something from a previous post, I suggest
posting a followup quoting the post and adding interspersed notes
as needed.

--
Keith Thompson (The_Other_Keith) Keith.S.T...@gmail.com
Working, but not speaking, for Philips Healthcare
void Void(void) { Void(); } /* The recursive call of the void */

olcott

unread,
Sep 9, 2020, 2:15:19 PM9/9/20
to
On 9/9/2020 12:46 PM, Keith Thompson wrote:
> olcott <No...@NoWhere.com> writes:
> [...]
>> It was a good idea to make it even clearer though so I updated it.
>> The std::vector array always knows its current size...
>
> You can't really update a Usenet post. What you did was post a
> new version of it, with no visible indication of what had changed.
> If you want to clarify something from a previous post, I suggest
> posting a followup quoting the post and adding interspersed notes
> as needed.
>

For cases like this one you are right.
I use the other new version convention when the discussion involves
hundreds of revisions that totally supersede and replace everything said
before.

wyn...@gmail.com

unread,
Sep 9, 2020, 4:25:20 PM9/9/20
to
olcott於 2020年9月10日星期四 UTC+8上午12時45分34秒寫道:
C++ is just combination of tricks, magic show, like all UTM's are
essentially the same. You can build your own C++ program without using "std::"
like I do (C++ may try to make this statement false). That said, GUI and thread
programing using C is a nightmare.
For learning c++, those fundamental ones (before c++11) should be sufficient
enough for most programmers.

olcott

unread,
Sep 9, 2020, 4:37:50 PM9/9/20
to
Before I found std::vector I utterly shunned all dynamic memory
allocation as a huge source of "make the system crash" errors.

Now that I have been programming in c++ for a couple of decades I never
use its destructors or "new". I always simply have a local stack
variable store the address of a std::vector on the stack. I never need
"new", I merely invoke the constructor of the object directly inside
push_back().

I even met Bjarne Stroustrup when he came to Omaha many years ago to
promote his new language: c++. He is a tee-shirt and blue jeans kind of
guy.

Mr Flibble

unread,
Sep 9, 2020, 5:10:10 PM9/9/20
to
We are not really interested in how you use C++ inappropriately. I suggest you lean how to use MODERN C++.

/Flibble

--
¬

olcott

unread,
Sep 9, 2020, 5:18:31 PM9/9/20
to
I created this thread because one of the respondents of these two groups
said that they would never bother to learn c++ because of the learning
curve of its enormous complexity. I am pointing out that "c" programmers
can get 90% of the benefit of c++ for 2% of the learning curve cost.

Using just the three aspects of c++ that I mentioned would make "c"
programs at least 500% more maintainable than their "c" counter parts.

Because "c" is a subset of c++, "c" programs can be gradually migrated
to the subset of c++ that I specified.

Juha Nieminen

unread,
Sep 10, 2020, 3:38:25 AM9/10/20
to
olcott <No...@nowhere.com> wrote:
> For all "c" programmers to get the maximum benfit from c++ with the
> least learning curve cost you only need to learn three things about c++
> (1) C++ classes
> (2) std::vector
> (3) std::string

If I were to give motivation for a C programmer to learn C++, it would be
something like this:

For starters, note that by using C++ you aren't giving up on anything that
you find nice, useful and handy in C. If something is, for example, very
efficient and/or simple to do in C, you can also do it in the exact same
way in C++. Also note that you don't need to compromise anything by
moving from C to C++.

For example: Do you find the printf() style of functions most convenient?
You don't have to give them up! Go straight ahead and use them in the exact
same way in C++. Or do you think that, for example, fread() is the best and
most efficient way to read a big bunch of data from a file? Well, you can
use it in the exact same way in C++, with no compromises.

(Perhaps the only thing that you would be giving up are VLAs, but good
arguments can be made, even in C, why they shouldn't be used. This is one
of the few things where Linus Torvalds is actually right.)

A C programmer could ask at this point: "Ok, so why *should* I move to C++
if I'm just going to use it to program in C?"

The reason is what standard C++ offers you *in addition* to C features,
which standard C does not. Once you get used to these handy features, it's
hard to go back to not having them.

The C++ standard library offers a lot of readymade, well-tested and for the
most part really efficient tools that the C standard library does not (and
for the most part cannot). The abovementioned std::vector and std::string
are but just a couple of examples. There are many more that are *actually*
useful in everyday coding, which allow you to do with one-liners things that
in C would require hundreds or even thousands of lines of code (especially
if you want the same efficiency).

(Of course not every tool is good for every single use case, but that's
normal and to be expected. This is true in programming in general: Not
every algorithm is good for every use case, not every data container type
is good for every use case. Know your tools, know how they work, know
what their strengths and weaknesses are, and choose the best tool for the
job. This is true in *all* of programming, not just C++. But when a
particular readymade tool is good for a particular task, it can save you
a huge amount of time and effort.)

The other great feature of C++ that C cannot offer is RAII: While it's most
often used for automatic memory and other resource management, it also has
other uses.

But even with just automatic memory management it can make your code
enormously simpler and safer. In C, dynamic memory management can be a real
nightmare, and very fragile in the sense that memory management bugs are
very easy to make inadvertently. The more complex your dynamic data
structures, the more complicated the memory management becomes, because
nothing of it can be automated.

In C++ it's very simple to have, let's say, a dynamically growing array
of struct objects, each object containing dynamically allocated strings
and dynamic arrays of other objects, which may themselves have dynamic
data containers inside them. All of this mess is automatically freed
when you remove elements from this array, or destroy the array itself.
In most cases you don't have to worry about it at all, nor write *any*
code to take care of freeing all these hundreds or thousands of allocated
memory blocks.

In C++ you can implement in a minute a really complicated hierarchy of
dynamic data structures containing dynamic data structures (multiple
layers deep), and with very simple code all of it is automatically
managed: When the outermost data container is destroyed, *all* of the
sub-objects, *all* of the other dynamic data containers within, all
the way down, are automatically destroyed. In most cases you don't need
to write a single line of code for this to happen.

And what's best is that none of that requires any compromise in
efficiency. The code generated by the compiler will be as efficient as
if you had done all that manually in C. (In fact, in many situations
the compiler may even be able to produce *more* efficient code than
a typical C implementation would.)

In other words, not only are you not giving up any features by moving
to C++ (other than VLAs), you also are not giving up any efficiency
by doing so.

David Brown

unread,
Sep 10, 2020, 6:01:01 AM9/10/20
to
On 10/09/2020 09:38, Juha Nieminen wrote:

(I'm snipping the rest of your post - which I think was rather good, but
I'm only keeping the bit I am commenting on.)

> (Perhaps the only thing that you would be giving up are VLAs, but good
> arguments can be made, even in C, why they shouldn't be used. This is one
> of the few things where Linus Torvalds is actually right.)
>
One subset of VLA's that are safe, convenient and efficient are when the
size of the array is from a "const" variable that is known at compile time:

void foo(void) {
const int sz = 100;
char vs[sz];
...
}

In C, "vs" is a VLA. In reality, the size is fully determined at
compile time, and it is valid as a normal non-VLA array in C++, since
C++ is more flexible about constant expressions.

Unless you are going to ban all local variables of array type, it makes
no sense to ban this kind of VLA in C programming - the safety,
semantics and (for a sane compiler with at least basic optimisation) the
resulting object code are the same as if "sz" were an enumeration
constant or a #define'd constant.

Juha Nieminen

unread,
Sep 10, 2020, 6:32:17 AM9/10/20
to
David Brown <david...@hesbynett.no> wrote:
> One subset of VLA's that are safe, convenient and efficient are when the
> size of the array is from a "const" variable that is known at compile time:
>
> void foo(void) {
> const int sz = 100;
> char vs[sz];
> ...
> }

If I understand correctly 'const' integer variables in C aren't really
considered compile-time constants (as they are in C++). Rather, 'const'
is more like an instruction to the compiler that tells it "give me
an error message at compile time if I ever try to assign something
to this", but otherwise it's pretty much a "normal" variable.

So I'm wondering what the C standard says about the above construct.
Is the compiler allowed to assume that 'sz' is a compile-time constant
and, thus, make 'vs' into a "regular" array (rather than a VLA)?

(I suppose that the standard does give this permission if it says
something along the lines of "modifying a variable declared as const
is UB", which essentially tells the compiler "you can assume its
value is what you see, it won't ever change".)

Richard Damon

unread,
Sep 10, 2020, 8:16:28 AM9/10/20
to
The compiler, via the 'as if' rule, can treat it like a fixed size
array. Only is cases where the difference makes a difference would it
need to treat it different.

For instance &vs does NOT match the type of a pointer to char[100], but
only to a pointer to char[sz]

David Brown

unread,
Sep 10, 2020, 8:30:20 AM9/10/20
to
On 10/09/2020 12:31, Juha Nieminen wrote:
> David Brown <david...@hesbynett.no> wrote:
>> One subset of VLA's that are safe, convenient and efficient are when the
>> size of the array is from a "const" variable that is known at compile time:
>>
>> void foo(void) {
>> const int sz = 100;
>> char vs[sz];
>> ...
>> }
>
> If I understand correctly 'const' integer variables in C aren't really
> considered compile-time constants (as they are in C++).

That is correct. In C++, "constant expression" is a very complicated
field, and there are lots of things that are constant expressions of
some kind. Very roughly, things the compiler can clearly know at
compile time are constant expressions. In C, "constant expression" is
far more limited and in particular, "const" variables are not "constant
expressions" (even if they are initialised with constant expressions and
local to the file or function).

> Rather, 'const'
> is more like an instruction to the compiler that tells it "give me
> an error message at compile time if I ever try to assign something
> to this", but otherwise it's pretty much a "normal" variable.

Yes, basically.

The compiler can often make assumptions that something that is declared
as "const" has a fixed and unchangeable value. Since there is no
(defined) way to change the value of "sz" in the function "foo" above,
the compiler can assume it is never changed.

>
> So I'm wondering what the C standard says about the above construct.
> Is the compiler allowed to assume that 'sz' is a compile-time constant
> and, thus, make 'vs' into a "regular" array (rather than a VLA)?

"vs" is still a VLA, and the code is only valid in standards and
compilers that support VLA's. But since there is no defined way to
change "sz", the compiler can generate code (and do things like bounds
checking for debugging) as though it were a normal fixed-size array.

This means the code generated is the same. But you can't have :

static const vs_sz = sizeof(vs);

because vs is a VLA, and thus "sizeof(vs)" is not a constant expression.
If sz had been defined as "enum { sz = 100 };" instead of "const int sz
= 100;", it would have been fine.

(It would be /really/ nice if a future C standard resolved this
silliness and made "const" work more like in C++, though of course not
changing the default linkage of file-level "const".)

>
> (I suppose that the standard does give this permission if it says
> something along the lines of "modifying a variable declared as const
> is UB", which essentially tells the compiler "you can assume its
> value is what you see, it won't ever change".)
>

Exactly.

olcott

unread,
Sep 10, 2020, 11:05:57 AM9/10/20
to
Also this library is so well written and designed that you can learn one
thing like std::vector in a few minutes and at the same time learn that
common interface to other library functions. You can learn this one
thing like std::vector without have to know anything else about the rest
of the library.
Hence my encouragement to use those two featuress.

> In C++ you can implement in a minute a really complicated hierarchy of
> dynamic data structures containing dynamic data structures (multiple
> layers deep), and with very simple code all of it is automatically
> managed: When the outermost data container is destroyed, *all* of the
> sub-objects, *all* of the other dynamic data containers within, all
> the way down, are automatically destroyed. In most cases you don't need
> to write a single line of code for this to happen.
>

I love this aspect. And no garbage collection cycles.

> And what's best is that none of that requires any compromise in
> efficiency. The code generated by the compiler will be as efficient as
> if you had done all that manually in C. (In fact, in many situations
> the compiler may even be able to produce *more* efficient code than
> a typical C implementation would.)
>
> In other words, not only are you not giving up any features by moving
> to C++ (other than VLAs), you also are not giving up any efficiency
> by doing so.
>

The reason that I loved C in the first place is that it was a much
easier way to write assembly language code. When you add just the three
things that I mentioned: classes, std::vector, std::string your C
programs become 500% more maintainable. The object oriented paradigm
reduces complexity by a whole other level. Now you have code and its
data packaged together.

Chris Vine

unread,
Sep 10, 2020, 4:04:19 PM9/10/20
to
On Thu, 10 Sep 2020 07:38:05 +0000 (UTC)
Juha Nieminen <nos...@thanks.invalid> wrote:
> olcott <No...@nowhere.com> wrote:
> > For all "c" programmers to get the maximum benfit from c++ with the
> > least learning curve cost you only need to learn three things about c++
> > (1) C++ classes
> > (2) std::vector
> > (3) std::string
>
> If I were to give motivation for a C programmer to learn C++, it would be
> something like this:
>
> For starters, note that by using C++ you aren't giving up on anything that
> you find nice, useful and handy in C. If something is, for example, very
> efficient and/or simple to do in C, you can also do it in the exact same
> way in C++. Also note that you don't need to compromise anything by
> moving from C to C++.
[snip]
> (Perhaps the only thing that you would be giving up are VLAs, but good
> arguments can be made, even in C, why they shouldn't be used. This is one
> of the few things where Linus Torvalds is actually right.)

Really? The first two examples below for constructing objects in
dynamically allocated memory or iterating pointers are wholly idiomatic
C, which most C programmers would regard as nice, useful and handy, but
give undefined behaviour in C++, and so probably ought to cause the
person you have encouraged to use C++ to lose their annual bonus (in
C++ the first requires placement new, and the second is only resolvable
in C++ by allocating the memory as an array of char using the new[]
expression and then incrementing by char* not int* (which leads to the
third point below, requiring std::launder):

int* i = (int*) malloc(sizeof(int));
*i = 0;

int* i = (int*) malloc(2 * (sizeof int));
i++;

Or a C programmer who knows that at some address held in a pointer
to char named 'ptr' there resides an int can safely write this in full
compliance with the strict aliasing rules:

int* i = (int*) ptr;
i* = 2;

In C++ this is undefined behaviour in any case where 'ptr' and 'i' are
not pointer-interconvertible unless you use std::launder.

Another example recently mentioned in this newsgroup which comes to mind
is type punning, where the C programmer will instinctively reach for a
union (which is permitted in C++ as an extension by gcc and clang but
not I believe by MSVC and is claimed by Stroustrup and others to have
undefined behaviour in standard C++).

I think your approach would be quite misleading. The languages are
now different at the most basic levels.

Keith Thompson

unread,
Sep 10, 2020, 4:08:25 PM9/10/20
to
Juha Nieminen <nos...@thanks.invalid> writes:
> David Brown <david...@hesbynett.no> wrote:
>> One subset of VLA's that are safe, convenient and efficient are when the
>> size of the array is from a "const" variable that is known at compile time:
>>
>> void foo(void) {
>> const int sz = 100;
>> char vs[sz];
>> ...
>> }
>
> If I understand correctly 'const' integer variables in C aren't really
> considered compile-time constants (as they are in C++). Rather, 'const'
> is more like an instruction to the compiler that tells it "give me
> an error message at compile time if I ever try to assign something
> to this", but otherwise it's pretty much a "normal" variable.

In C, "const" doesn't mean "constant". It means read-only.

`sz` is not a constant expression. `char vs[sz];` is a valid
declaration if and only if VLAs are supported (not supported in C90,
supported in C99, optional in C11).

If VLAs are supported a compiler can generate exactly the same code for
this that it would generate for `char vs[100];`. (I might be able to
create a highly contrived case where the behavior *might* be different
based on the poorly worded rule about evaluating the operand of sizeof.)

> So I'm wondering what the C standard says about the above construct.
> Is the compiler allowed to assume that 'sz' is a compile-time constant
> and, thus, make 'vs' into a "regular" array (rather than a VLA)?

`sz` is a VLA. For (almost) all purposes, this doesn't make any visible
difference for a compiler that supports VLAs. For a compiler that
doesn't support VLAs (e.g., a conforming C11 compiler that predefines
__STDC_NO_VLA__), the declaration is a constraint violation and a
diagnostic is required.

> (I suppose that the standard does give this permission if it says
> something along the lines of "modifying a variable declared as const
> is UB", which essentially tells the compiler "you can assume its
> value is what you see, it won't ever change".)

Yes.

(In C++, the rules for constant expressions cause `sz` to be
a constant expression, so `char vs[sz];` defines an ordinary
non-VLAs array. As I understand it, this is something of a special
case; `const` still means read-only in most cases. For example,
`const int r = rand();` is valid in both C and C++ and does not make
`r` a constant expression. I personally would have preferred if C++
had not introduced this special case, and instead used `constexpr`
for this purpose -- but `constexpr` wasn't introduced until after
the rule was added. I would have advocated spelling "const" as
"readonly" if not for the fact that it would have broken existing
code.)

olcott

unread,
Sep 10, 2020, 4:36:21 PM9/10/20
to
On 9/10/2020 3:03 PM, Chris Vine wrote:
> On Thu, 10 Sep 2020 07:38:05 +0000 (UTC)
> Juha Nieminen <nos...@thanks.invalid> wrote:
>> olcott <No...@nowhere.com> wrote:
>>> For all "c" programmers to get the maximum benfit from c++ with the
>>> least learning curve cost you only need to learn three things about c++
>>> (1) C++ classes
>>> (2) std::vector
>>> (3) std::string
>>
>> If I were to give motivation for a C programmer to learn C++, it would be
>> something like this:
>>
>> For starters, note that by using C++ you aren't giving up on anything that
>> you find nice, useful and handy in C. If something is, for example, very
>> efficient and/or simple to do in C, you can also do it in the exact same
>> way in C++. Also note that you don't need to compromise anything by
>> moving from C to C++.
> [snip]
>> (Perhaps the only thing that you would be giving up are VLAs, but good
>> arguments can be made, even in C, why they shouldn't be used. This is one
>> of the few things where Linus Torvalds is actually right.)
>
> Really? The first two examples below for constructing objects in
> dynamically allocated memory or iterating pointers are wholly idiomatic

Can be bypassed by constructing the object directly within a
std::vector.push_back(INVOKE CONSTRUCTOR HERE) and using std::vector
array subscript interface to iterate over the objects in the vector.

Chris Vine

unread,
Sep 10, 2020, 4:50:44 PM9/10/20
to
C++'s facilties for using and managing dynamically allocated memory are
indeed superior to C's, but I wasn't commenting on that. I was
commenting on the fact that the appeal to C programmers in these terms
is false:

"For starters, note that by using C++ you aren't giving up on anything
that you find nice, useful and handy in C. If something is, for
example, very efficient and/or simple to do in C, you can also do it
in the exact same way in C++".

You can do the things I mentioned in a different way in C++, but not in
"the exact same way", nor even in inexactly the same way. More
strickingly, allocating objects in dynamically allocated memory is
ubiquitous in both C and C++, but the only way to do so in C gives rise
to undefined behaviour in C++, even if the objects are C-like
(so-called trivial objects).

olcott

unread,
Sep 10, 2020, 5:05:56 PM9/10/20
to
Not in the terms that I originally specified.

I have been a very productive C++ programmer for two decades hardly ever
needing more than those three things. Someone else on my request wrote a
very superb two-dimensional std::vector for me in this forum, even then
I did not need to touch templates myself.

With just the tiniest little bit of learning curve C programmers can
start writing their same programs much more effectively in C++.

I have never ever had to do any dynamic memory allocation in any of my
own code.

> "For starters, note that by using C++ you aren't giving up on anything
> that you find nice, useful and handy in C. If something is, for
> example, very efficient and/or simple to do in C, you can also do it
> in the exact same way in C++".
>
> You can do the things I mentioned in a different way in C++, but not in
> "the exact same way", nor even in inexactly the same way. More
> strickingly, allocating objects in dynamically allocated memory is
> ubiquitous in both C and C++, but the only way to do so in C gives rise
> to undefined behaviour in C++, even if the objects are C-like
> (so-called trivial objects).
>


Chris Vine

unread,
Sep 10, 2020, 5:25:15 PM9/10/20
to
On Thu, 10 Sep 2020 16:05:35 -0500
olcott <No...@NoWhere.com> wrote:
[snip]
> >>>> If I were to give motivation for a C programmer to learn C++, it would be
> >>>> something like this:
> >>>>
> >>>> For starters, note that by using C++ you aren't giving up on anything that
> >>>> you find nice, useful and handy in C. If something is, for example, very
> >>>> efficient and/or simple to do in C, you can also do it in the exact same
> >>>> way in C++. Also note that you don't need to compromise anything by
> >>>> moving from C to C++.
> >>> [snip]
> >>>> (Perhaps the only thing that you would be giving up are VLAs, but good
> >>>> arguments can be made, even in C, why they shouldn't be used. This is one
> >>>> of the few things where Linus Torvalds is actually right.)
> >>>
> >>> Really? The first two examples below for constructing objects in
> >>> dynamically allocated memory or iterating pointers are wholly idiomatic
> >>
> >> Can be bypassed by constructing the object directly within a
> >> std::vector.push_back(INVOKE CONSTRUCTOR HERE) and using std::vector
> >> array subscript interface to iterate over the objects in the vector.
> >
> > C++'s facilties for using and managing dynamically allocated memory are
> > indeed superior to C's, but I wasn't commenting on that. I was
> > commenting on the fact that the appeal to C programmers in these terms
> > is false:
>
> Not in the terms that I originally specified.

In my posting about C++'s differences from C I wasn't responding to you.

I am sure your views are interesting, but they are irrelevant to my
posting, and you have contrived to elide the part of my posting which
made that evident. I hope your halting logic is better.

olcott

unread,
Sep 10, 2020, 5:35:18 PM9/10/20
to
I was staying on topic for this thread.

My primary point in this thread is that the most essential aspects of
C++ can be learned by C programmers in a few hours so that these C
programmers can begin migrating their C code to C++ and reap amazing
benefits.

> I am sure your views are interesting, but they are irrelevant to my
> posting, and you have contrived to elide the part of my posting which
> made that evident. I hope your halting logic is better.
>


Chris Vine

unread,
Sep 10, 2020, 5:39:51 PM9/10/20
to
On Thu, 10 Sep 2020 16:34:57 -0500
olcott <No...@NoWhere.com> wrote:
> My primary point in this thread is that the most essential aspects of
> C++ can be learned by C programmers in a few hours so that these C
> programmers can begin migrating their C code to C++ and reap amazing
> benefits.

Happily, newsnet does not provide for ownership of topics by
the self-absorbed, or by anyone else for that matter.

olcott

unread,
Sep 10, 2020, 6:10:51 PM9/10/20
to
I made a good case for C programmers to learn C++.

The key aspect of this case is that the most useful aspects of C++ have
very little learning curve cost such that existing C programs can be
gradually migrated to this subset of of C++ drastically improving the
quality and maintainability of these programs.

Chris Vine

unread,
Sep 10, 2020, 6:27:12 PM9/10/20
to
On Thu, 10 Sep 2020 17:10:30 -0500
olcott <No...@NoWhere.com> wrote:
> On 9/10/2020 4:39 PM, Chris Vine wrote:
> > On Thu, 10 Sep 2020 16:34:57 -0500
> > olcott <No...@NoWhere.com> wrote:
> >> My primary point in this thread is that the most essential aspects of
> >> C++ can be learned by C programmers in a few hours so that these C
> >> programmers can begin migrating their C code to C++ and reap amazing
> >> benefits.
> >
> > Happily, newsnet does not provide for ownership of topics by
> > the self-absorbed, or by anyone else for that matter.
> >
>
> I made a good case for C programmers to learn C++.

Do you seriously think anyone was in doubt about what you were trying
to do? Get a clue and try to stop trying to take over other people's
conversations.

olcott

unread,
Sep 10, 2020, 6:43:16 PM9/10/20
to
This is my thread and my conversation. If you want to change the subject
then indicate that by appended the change to the subject, otherwise your
comments of are off-topic.

Chris Vine

unread,
Sep 10, 2020, 6:50:11 PM9/10/20
to
On Thu, 10 Sep 2020 17:42:56 -0500
olcott <No...@NoWhere.com> wrote:
> This is my thread and my conversation. If you want to change the subject
> then indicate that by appended the change to the subject, otherwise your
> comments of are off-topic.

Nope. The comments to which I was responding, and my own comments, were
on topic so it would be pointless changing the subject. They just
didn't happen to be your comments. As I said, newsnet does not provide
for ownership of topics by the self-absorbed.

Stop behaving like a mono-maniac and your life will be happier.

olcott

unread,
Sep 10, 2020, 6:55:25 PM9/10/20
to
I read what you said this this. It was fine.
There are too many people that came to this thread saying very
discouraging words to prospective C++ programmers.

olcott

unread,
Sep 10, 2020, 7:01:40 PM9/10/20
to
I carefully read your comments this time. They were fine.

Juha Nieminen

unread,
Sep 11, 2020, 3:28:14 AM9/11/20
to
Chris Vine <chris@cvine--nospam--.freeserve.co.uk> wrote:
> int* i = (int*) malloc(sizeof(int));
> *i = 0;
>
> int* i = (int*) malloc(2 * (sizeof int));
> i++;
>
> int* i = (int*) ptr;
> i* = 2;

Can you give an example of any C++ compiler on any platform that would
behave differently when compiling those as C++ than when compiling them
as C?

David Brown

unread,
Sep 11, 2020, 5:09:17 AM9/11/20
to
Alternatively, an explanation (ideally with references) as to why they
might be different would be nice.

I am not entirely fluent in the details of POD, standard layout, trivial
types, etc., (especially as these details have changed with different
standards versions), but for scalar types like "int" this kind of thing
should work identically in C and C++ AFAIK.

That is, the first two should work fine (assuming malloc returns
something other than a null pointer), and the third is fine as long as
"ptr" holds an address that points to an "int" (that bit was skipped by
the quotation snipping).

Chris Vine

unread,
Sep 11, 2020, 6:18:08 AM9/11/20
to
On Fri, 11 Sep 2020 11:08:57 +0200
David Brown <david...@hesbynett.no> wrote:
> On 11/09/2020 09:27, Juha Nieminen wrote:
> > Chris Vine <chris@cvine--nospam--.freeserve.co.uk> wrote:
> >> int* i = (int*) malloc(sizeof(int));
> >> *i = 0;
> >>
> >> int* i = (int*) malloc(2 * (sizeof int));
> >> i++;
> >>
> >> int* i = (int*) ptr;
> >> i* = 2;
> >
> > Can you give an example of any C++ compiler on any platform that would
> > behave differently when compiling those as C++ than when compiling them
> > as C?
> >
>
> Alternatively, an explanation (ideally with references) as to why they
> might be different would be nice.

They are different in C++20 because that is what the C++ standard
committee hath wrought, foolishly in my opinion. This code ought to be
valid C++. (The reference is [intro.object]/1, if that is what you
were after.)

> I am not entirely fluent in the details of POD, standard layout, trivial
> types, etc., (especially as these details have changed with different
> standards versions), but for scalar types like "int" this kind of thing
> should work identically in C and C++ AFAIK.

I agree that it should do. Unfortunately it doesn't.

> That is, the first two should work fine (assuming malloc returns
> something other than a null pointer), and the third is fine as long as
> "ptr" holds an address that points to an "int" (that bit was skipped by
> the quotation snipping).

The third (snipped) example is invalid because according to C++17 and
C++20 you can only carry out pointer arithmatic on a pointer which
results in an address within the range of an array (including one past
the end) ([expr.add]/4) and "Otherwise, the behavior is undefined" for
pointer arithmetic. Memory returned by malloc (and operator new for
that matter) is not an array. You are right that an object that is not
an array element whose address is taken by the unary & operator is
considered to belong to an array with one element of type T for the
purposes of pointer arithmetic on the value returned by that operator:
in such a case you can add 1 to the address of the object.

That doesn't apply here, but where it does, given an object 'o' then
'&o+1' can be valid whereas '&o+2' is not, even in cases where the
result of both point within properly malloc'ed memory. Even for '&o+1'
to work you would have to construct an object (here an int) in the
malloc'ed memory using placement new first. Note that this is not about
dereferencing the pointer (where obviously an object is required) but
about the mere act of carrying out pointer arithmetic on a pointer.

Frankly, this result is unintuitive and absurd. Pointer arithmetic
within memory duly allocated by malloc or operator new should be
allowed. And, to go back to the original point, C++ is incompatible
with C on this, apparently deliberately so. You cannot "do it in the

Chris Vine

unread,
Sep 11, 2020, 6:50:10 AM9/11/20
to
Sorry I got my numbering wrong. The preceding two paragraphs are about
the second example, not the third.

As to the third example, you can according to C++20 construct an int in
a dynamically allocated array of char (the example I gave). But to
access it by a cast of the char* (as opposed to using the pointer to
int returned by the use of placement new to construct the int), you
must use std::launder as well as make the cast, because the pointers
are not pointer-interconvertible - it is no longer sufficient just to
comply with the strict aliasing rules as in C. This is the combined
effect of [basic.compound]/4 and [ptr.launder]. The
pointer-interconvertibility rules were brought in in C++17.

bol...@nuttyella.co.uk

unread,
Sep 11, 2020, 7:21:27 AM9/11/20
to
On Fri, 11 Sep 2020 11:17:46 +0100
Chris Vine <chris@cvine--nospam--.freeserve.co.uk> wrote:
>On Fri, 11 Sep 2020 11:08:57 +0200
>That doesn't apply here, but where it does, given an object 'o' then
>'&o+1' can be valid whereas '&o+2' is not, even in cases where the
>result of both point within properly malloc'ed memory. Even for '&o+1'
>to work you would have to construct an object (here an int) in the
>malloc'ed memory using placement new first. Note that this is not about
>dereferencing the pointer (where obviously an object is required) but
>about the mere act of carrying out pointer arithmetic on a pointer.

It makes you wonder if the committee really don't like pointers at all and
are making it as obnoxious as possible to use them in order to discourage it
and eventually deprecate them.

Given how tricky pointers can be for learners all it'll do is make even
more potential C++ devs flee to other languages with fewer BS rules-for-their-
own-sake and sphagetti syntax. Certainly if I was starting out today and
wondering which language to learn C++ would not be top of the list.

David Brown

unread,
Sep 11, 2020, 11:29:12 AM9/11/20
to
On 11/09/2020 12:17, Chris Vine wrote:
> On Fri, 11 Sep 2020 11:08:57 +0200
> David Brown <david...@hesbynett.no> wrote:
>> On 11/09/2020 09:27, Juha Nieminen wrote:
>>> Chris Vine <chris@cvine--nospam--.freeserve.co.uk> wrote:
>>>> int* i = (int*) malloc(sizeof(int));
>>>> *i = 0;
>>>>
>>>> int* i = (int*) malloc(2 * (sizeof int));
>>>> i++;
>>>>
>>>> int* i = (int*) ptr;
>>>> i* = 2;
>>>
>>> Can you give an example of any C++ compiler on any platform that would
>>> behave differently when compiling those as C++ than when compiling them
>>> as C?
>>>
>>
>> Alternatively, an explanation (ideally with references) as to why they
>> might be different would be nice.
>
> They are different in C++20 because that is what the C++ standard
> committee hath wrought, foolishly in my opinion. This code ought to be
> valid C++. (The reference is [intro.object]/1, if that is what you
> were after.)
>

I haven't looked in detail at C++20 (and I haven't read all the details
of any other C++ standards - there's just too much there). Usually I
get what I need from looking at the lists of changes and new features,
along with <https://en.cppreference.com>, and nothing I have seen in
these sources indicates anything you mention here.

But now I have N4860 open, and I'm looking at 6.7.2 "intro.object". In
p10-p12, there is a discussion of "implicitly creating objects" and
there is this example:


#include <cstdlib>
struct X { int a, b; };
X *make_x() {
// The call to std::malloc implicitly creates an object of type X
// and its subobjects a and b, and returns a pointer to that X
// object
// (or an object that is pointer-interconvertible (6.8.2) with it),
// in order to give the subsequent class member access operations
// defined behavior.

X *p = (X*)std::malloc(sizeof(struct X));
p->a = 1;
p->b = 2;
return p
}

I can't see any way to rationalise this example being valid and defined
behaviour, but your first two examples being a problem or in any way
different from the behaviour in C.

(I'm not saying you are wrong here - but you might be, and I think we
both hope that you /are/ wrong.)



>> I am not entirely fluent in the details of POD, standard layout, trivial
>> types, etc., (especially as these details have changed with different
>> standards versions), but for scalar types like "int" this kind of thing
>> should work identically in C and C++ AFAIK.
>
> I agree that it should do. Unfortunately it doesn't.
>
>> That is, the first two should work fine (assuming malloc returns
>> something other than a null pointer), and the third is fine as long as
>> "ptr" holds an address that points to an "int" (that bit was skipped by
>> the quotation snipping).
>
> The third (snipped) example is invalid because according to C++17 and
> C++20 you can only carry out pointer arithmatic on a pointer which
> results in an address within the range of an array (including one past
> the end) ([expr.add]/4) and "Otherwise, the behavior is undefined" for
> pointer arithmetic.

That is the same in C. (A pointer to a single object can be viewed as
an array of length 1 in this context.)

And the third example doesn't have pointer arithmetic, and it is not
snipped. Are you talking about a different example that has got lost
somewhere, and are counting differently from me? (Maybe you are
counting from zero...)


> Memory returned by malloc (and operator new for
> that matter) is not an array. You are right that an object that is not
> an array element whose address is taken by the unary & operator is
> considered to belong to an array with one element of type T for the
> purposes of pointer arithmetic on the value returned by that operator:
> in such a case you can add 1 to the address of the object.
>

In the section of N4860 referenced, it is clear that "malloc" is
considered to "implicitly create objects", and that you can cast the
returned void* pointer to other types and access data that way.

> That doesn't apply here, but where it does, given an object 'o' then
> '&o+1' can be valid whereas '&o+2' is not, even in cases where the
> result of both point within properly malloc'ed memory.

Are you suggesting that if you do a malloc (of suitable size) and cast
the returned pointer to T*, this is only valid as a pointer to a single
T and not the start of an array of T's ? I don't believe that is
correct, though I haven't dug through chapter and verse, and I don't
think the meaning has changed for different C++ standards or between C
and C++.

James Kuyper

unread,
Sep 11, 2020, 11:45:19 AM9/11/20
to
On 9/11/20 6:17 AM, Chris Vine wrote:
> On Fri, 11 Sep 2020 11:08:57 +0200
> David Brown <david...@hesbynett.no> wrote:
>> On 11/09/2020 09:27, Juha Nieminen wrote:
>>> Chris Vine <chris@cvine--nospam--.freeserve.co.uk> wrote:
>>>> int* i = (int*) malloc(sizeof(int));
>>>> *i = 0;
>>>>
>>>> int* i = (int*) malloc(2 * (sizeof int));
>>>> i++;
>>>>
>>>> int* i = (int*) ptr;
>>>> i* = 2;
...
> They are different in C++20 because that is what the C++ standard
> committee hath wrought, foolishly in my opinion. This code ought to be
> valid C++. (The reference is [intro.object]/1, if that is what you
> were after.)

Where can I obtain a copy of that version of the standard? I couldn't
find it on the working group's web site, which is where I usually go. It
doesn't have to be the actual current standard; a sufficiently recent
draft would be sufficient.

...
> The third (snipped) example is invalid because according to C++17 and
> C++20 you can only carry out pointer arithmatic on a pointer which
> results in an address within the range of an array (including one past
> the end) ([expr.add]/4) and "Otherwise, the behavior is undefined" for
> pointer arithmetic. Memory returned by malloc (and operator new for
> that matter) is not an array.

Do you mean "second example"? Tracing back, only the second example
involve pointer arithmentic (i++).
That is just as much a problem with C as with C++. For pointer values,
they both define i++ as equivalent to i=i+1, except that 'i' is
evaluated only once, and they both define addition of integer values to
pointer values in terms of a containing array; if there's no such array,
there's no applicable definition of what the addition means.

> ... You are right that an object that is not
> an array element whose address is taken by the unary & operator is
> considered to belong to an array with one element of type T for the
> purposes of pointer arithmetic on the value returned by that operator:
> in such a case you can add 1 to the address of the object.
>
> That doesn't apply here,

In n3797.pdf, the relevant wording is "For the purposes of these
operators, a pointer to a nonarray object behaves the same as a pointer
to the first element of an array of length one with the type of the
object as its element type." (5.7p4), which seems perfectly applicable.
That wording does not include the part from your explanation requiring
that it be the result of the unary & operator; all that's required is
that it be "a pointer to a non-array object". How is the wording in
C++2020 different, to render that clause inapplicable?

Brian Wood

unread,
Sep 11, 2020, 1:22:33 PM9/11/20
to
On Wednesday, September 9, 2020 at 11:45:34 AM UTC-5, olcott wrote:
> For all "c" programmers to get the maximum benfit from c++ with the
> least learning curve cost you only need to learn three things about c++
> (1) C++ classes
> (2) std::vector
> (3) std::string
>
> I spoke with someone on the comp.lang.c recently about the benefits of
> c++. Her objections was that c++ has a huge learning curve.
>
> I have been a "c" programmer since K&R was the official standard and
> only learned those very few things about c++ that make programming much
> easier. In two decades as a c++ programmer I don't hardly use anything
> else besides those three things.
>
> I learned about c++ classes, std::vector and std::string, that is the
> tiny subset of c++ that makes "c" programming much easier. I have
> continued to use the stdio.h I/O library of "c" in all my c++ programs.
> I just started calling this library <cstdio> by its c++ name.
>
> C++ classes implement the key most important and useful aspect of Object
> Oriented Programming (OOP). I have never found any other aspect of OOP
> useful.
>
> C++ classes are just "c" structs having their own member functions that
> operate only on this data. Code and data can be kept together in the
> same place eliminating the possibility of data dependency side-effects.
> With OOP you can create self-contained units of modularity. This is ht e
> greatest thing about c++ and OOP.
>
> With std::vector you can have an array of anything that totally handles
> all of its own memory management that can be kept in a tiny little
> pointer in a stack (local) variable. You can use normal "c" substripts
> to access elements.
>
> The array always knows its current size: size() and you can append
> another element with memory management automatically handled for you
> with push_back(). The allocation algorithm is an optimal balance between
> time and space can be easily superseded with resize() or reserve().
>
> std::string is a string of characters that can grow as large as needed
> and has the same interface as std::vector. The above three things is all
> the c++ that "c" programmer ever needs to know.
>
> --
> Copyright 2020 Pete Olcott

There's some effort to tie OOP to C++ like an anchor
around it's neck. Probably this comes from authors of
competing languages.

The jury is still out on 2020 C++, so I suggest using
an older version.

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

Chris Vine

unread,
Sep 11, 2020, 2:58:56 PM9/11/20
to
On Fri, 11 Sep 2020 11:44:54 -0400
James Kuyper <james...@alumni.caltech.edu> wrote:
> On 9/11/20 6:17 AM, Chris Vine wrote:
> > On Fri, 11 Sep 2020 11:08:57 +0200
> > David Brown <david...@hesbynett.no> wrote:
> >> On 11/09/2020 09:27, Juha Nieminen wrote:
> >>> Chris Vine <chris@cvine--nospam--.freeserve.co.uk> wrote:
> >>>> int* i = (int*) malloc(sizeof(int));
> >>>> *i = 0;
> >>>>
> >>>> int* i = (int*) malloc(2 * (sizeof int));
> >>>> i++;
> >>>>
> >>>> int* i = (int*) ptr;
> >>>> i* = 2;
> ...
> > They are different in C++20 because that is what the C++ standard
> > committee hath wrought, foolishly in my opinion. This code ought to be
> > valid C++. (The reference is [intro.object]/1, if that is what you
> > were after.)
>
> Where can I obtain a copy of that version of the standard? I couldn't
> find it on the working group's web site, which is where I usually go. It
> doesn't have to be the actual current standard; a sufficiently recent
> draft would be sufficient.

The closest to C++20 was N4849. Stimulated by David Brown I have now
got hold of N4860. Assuming that that actually represents the final
version of C++20 put to international ballot, it has considerable
changes voted in at the last moment, probably in answer to
http://wg21.link/p0593r6 , which pointed out the considerable
deficiencies in C++17 and in the then draft standard respecting
trivial objects.

If so, that is surprising, as P0593r6 said:

"This paper did not complete LWG review in time for C++20. However,
the functionality contained herein can be split into two portions:

The core language change that gives defined behavior to various
constructs that have historically been assumed to work, and

...

The author suggests that the committee considers adopting the former
portion of this paper as a Defect Report, for possible inclusion into
the C++20 IS, and that the latter portion be deferred to C++23."

Maybe N4860 is C++20 plus defect report but it looks like the final
version. No doubt in due course all will be revealed.

> ...
> > The third (snipped) example is invalid because according to C++17 and
> > C++20 you can only carry out pointer arithmatic on a pointer which
> > results in an address within the range of an array (including one past
> > the end) ([expr.add]/4) and "Otherwise, the behavior is undefined" for
> > pointer arithmetic. Memory returned by malloc (and operator new for
> > that matter) is not an array.
>
> Do you mean "second example"? Tracing back, only the second example
> involve pointer arithmentic (i++).
> That is just as much a problem with C as with C++. For pointer values,
> they both define i++ as equivalent to i=i+1, except that 'i' is
> evaluated only once, and they both define addition of integer values to
> pointer values in terms of a containing array; if there's no such array,
> there's no applicable definition of what the addition means.

Yes I did mean the second example. The point about C11 is that
§6.5.6/8 deals with pointer arithmetic concerning arrays and the words
"otherwise, the behavior is undefined" seem to have been read in the
context of arrays only and not applying to raw malloc'ed memory. That
reading is impossible with C++20's [expr.add]/4. The issue with C is
also that the "effective type" of raw memory is normally the type of
the first object constructed in it (§6.5/6 of C11), so in a sense
malloc'ed memory becomes an array in C by being treated as an array.
(Somewhat akin to the new C++ implicit-lifetime types.)

At any rate I doubt you will find any C programmer, or member of the C
standard committee, who thinks that:

int* i = (int*) malloc(2 * sizeof(int));
i++;

is undefined behaviour because of §6.5.6/8, as in C it is the only way
of getting to the second element in advance of constructing the first
one.

If N4860 is the definitive text for C++20, then I think this construct
now has defined behaviour in C++20 because an array would implicitly be
taken to arise for the case of an array of trivial types, given that
array types are now implicit-lifetime types. I will need to consider
revised [intro.object]/10 further on this.

> > ... You are right that an object that is not
> > an array element whose address is taken by the unary & operator is
> > considered to belong to an array with one element of type T for the
> > purposes of pointer arithmetic on the value returned by that operator:
> > in such a case you can add 1 to the address of the object.
> >
> > That doesn't apply here,
>
> In n3797.pdf, the relevant wording is "For the purposes of these
> operators, a pointer to a nonarray object behaves the same as a pointer
> to the first element of an array of length one with the type of the
> object as its element type." (5.7p4), which seems perfectly applicable.
> That wording does not include the part from your explanation requiring
> that it be the result of the unary & operator; all that's required is
> that it be "a pointer to a non-array object". How is the wording in
> C++2020 different, to render that clause inapplicable?

My meaning was that it was not applicable to my example, which did not
involve construction of an object.

Chris Vine

unread,
Sep 11, 2020, 2:58:57 PM9/11/20
to
On Fri, 11 Sep 2020 17:28:51 +0200
Compare N4849 and C++17. This is either a very last minute change to
the draft standard before it was put to international ballot, or it
represents the inclusion of a defect report not in the actual balloted
standard. This is clearly in response to http://wg21.link/p0593r6 (it
incorporates the proposed wording in that document), which pointed out
the considerable deficiencies in C++17 and in the then draft standard
respecting trivial objects. P0593r6 indicates that its proposals were
too late to make the cut for C++20. Maybe the then draft standard
N4849 was thought to be so defective in the light of the report as to
need urgent rule bending. It is good to see nonetheless.

It clearly deals with my first example. It probably deals with my
second example (pointer arithmetic) but I would need to consider that
further. It obviously doesn't deal with my third point (the rules on
pointer interconvertibility and std::launder as an addition to the
strict aliasing rules).

David Brown

unread,
Sep 11, 2020, 6:04:11 PM9/11/20
to
On 11/09/2020 20:57, Chris Vine wrote:
> On Fri, 11 Sep 2020 11:44:54 -0400
> James Kuyper <james...@alumni.caltech.edu> wrote:

>> Where can I obtain a copy of that version of the standard? I couldn't
>> find it on the working group's web site, which is where I usually go. It
>> doesn't have to be the actual current standard; a sufficiently recent
>> draft would be sufficient.
>
> The closest to C++20 was N4849. Stimulated by David Brown I have now
> got hold of N4860. Assuming that that actually represents the final
> version of C++20 put to international ballot, it has considerable
> changes voted in at the last moment, probably in answer to
> http://wg21.link/p0593r6 , which pointed out the considerable
> deficiencies in C++17 and in the then draft standard respecting
> trivial objects.
>

For your convenience (I certainly find it convenient), I found the link
from:

<https://en.cppreference.com/w/cpp/links>

This labels N4860 as "C++20 final working draft". I don't know any more
details than that.

Chris Vine

unread,
Sep 11, 2020, 6:31:43 PM9/11/20
to
Given that that document has a ISO copyright notice in respect of
which the link appears to be in flagrant breach, that looks a bit dodgy
to me. But hey, if you can alter an international treaty what's an ISO
publication ...

Richard Damon

unread,
Sep 11, 2020, 7:22:32 PM9/11/20
to
Since the link goes to iso.org, and you are downloading it from the ISO
server, I don't think they can make much of a copyright violation claim
for you downloading it.

The COULD go after you, if you did something like try to sell to
someone, maybe after small edit to make it look like the actual standard
instead of the final draft.

ISO seems to have a policy that the drafts are free, but the published
standards are expensive. For most people, the final drafts are good
enough, so they can get it for free. For the companies that the
difference is important, the price of the Standard isn't that significant.

David Brown

unread,
Sep 12, 2020, 7:49:41 AM9/12/20
to
The "cppreference" webpage is made in cooperation with the C++ and C
standards groups - it is the nearest thing there is to an official
reference wifi for the languages. You can be fairly confident that the
working groups not only know about these links, but are involved in
keeping them updated. Many of the links on that page go directly to ISO
and WG webpages and publications. And N4680 is freely available from,
amongst other places,
<https://isocpp.org/blog/2020/04/2020-04-mailing-available>.

The C++ and C ISO groups and working groups are interested in making the
standards as freely and widely available as possible. The rules of ISO
require that the final official published standards cost money, but at
least for C and C++, that is seen as a formality rather than a source of
income.

Chris Vine

unread,
Sep 12, 2020, 9:23:37 AM9/12/20
to
On Sat, 12 Sep 2020 13:49:18 +0200
David Brown <david...@hesbynett.no> wrote:
> On 12/09/2020 00:31, Chris Vine wrote:
[snip]
> > Given that that document has a ISO copyright notice in respect of
> > which the link appears to be in flagrant breach, that looks a bit dodgy
> > to me. But hey, if you can alter an international treaty what's an ISO
> > publication ...
> >
>
> The "cppreference" webpage is made in cooperation with the C++ and C
> standards groups - it is the nearest thing there is to an official
> reference wifi for the languages. You can be fairly confident that the
> working groups not only know about these links, but are involved in
> keeping them updated. Many of the links on that page go directly to ISO
> and WG webpages and publications. And N4680 is freely available from,
> amongst other places,
> <https://isocpp.org/blog/2020/04/2020-04-mailing-available>.
>
> The C++ and C ISO groups and working groups are interested in making the
> standards as freely and widely available as possible. The rules of ISO
> require that the final official published standards cost money, but at
> least for C and C++, that is seen as a formality rather than a source of
> income.

If that is the intention, which seems laudable, rather better not to
include a copyright notice on this particular document (N4860) which
says amongst other things "All rights reserved. Unless otherwise
specified, no part of this publication may be reproduced or utilized
otherwise in any form or by any means, electronic or mechanical,
including photocopying, or posting on the internet or an intranet,
without prior written permission."

The English is somewhat defective, but not being able to "utilize" it in
any form without prior written permission by ISO rather negates their
making it downloadable on the internet in the first place, and taken
literally would seem to prevent you from having extracted from it and
commenting on it in your earlier posting, and possibly from having
read the document you downloaded in the first place. No doubt (i) in
practice some kind of right of fair use arises, and (ii) the notice
is in some kind of standard form which they do not intend to be taken
seriously until they do decide to take it seriously. Maybe they would
do better with some kind of Creative Commons licence for draft
documents - I notice that the "normal" drafts contain no copyright
notice at all.

David Brown

unread,
Sep 12, 2020, 1:10:43 PM9/12/20
to
Perhaps. But I suppose as a draft ISO document, it contains the same
copyright notice as the ISO document itself.

Certainly the working groups make these all available. They even make
the source (in LaTeX) available on GitHub.

>
> The English is somewhat defective, but not being able to "utilize" it in
> any form without prior written permission by ISO rather negates their
> making it downloadable on the internet in the first place, and taken
> literally would seem to prevent you from having extracted from it and
> commenting on it in your earlier posting, and possibly from having
> read the document you downloaded in the first place. No doubt (i) in
> practice some kind of right of fair use arises, and (ii) the notice
> is in some kind of standard form which they do not intend to be taken
> seriously until they do decide to take it seriously. Maybe they would
> do better with some kind of Creative Commons licence for draft
> documents - I notice that the "normal" drafts contain no copyright
> notice at all.
>

It is normal for draft documents to have the same types of copyright
notice as finished documents.

Richard Damon

unread,
Sep 12, 2020, 1:31:48 PM9/12/20
to
But due to how copyright works, if they put a Creative Commons license
on the draft, the fact that the final version is essentially identical
to the final draft, in might impede there ability to enforce copyright
on the official release.

Another thing to consider is that despite what clause says, there are
implied "Fair Use" rights that people have, especially if the copyright
holder intentionally puts the document out on a public facing website.

Bo Persson

unread,
Sep 12, 2020, 2:46:27 PM9/12/20
to
If you don't like the ISO legalese, you can try the document N4861
instead. It is a "working material", which doesn't have the ISO front
cover, but is otherwise identical.


Bo Persson

unread,
Sep 12, 2020, 2:50:12 PM9/12/20
to
And, BTW, it seems like N4860 has now been password protected, which it
should probably have been from the beginning. :-)



Bo Persson

Keith Thompson

unread,
Sep 12, 2020, 6:00:41 PM9/12/20
to
Richard Damon <Ric...@Damon-Family.org> writes:
[...]
> Another thing to consider is that despite what clause says, there are
> implied "Fair Use" rights that people have, especially if the copyright
> holder intentionally puts the document out on a public facing website.

My limited understanding is that the Fair Use doctrine does not allow
for distributing an entire work. Please don't take my work for this.

"Fair Use" seems to be a widely misunderstood concept. I suggest that
doing your own research or seeking out a forum where it's topical would
be more productive that trying to discuss it here.

--
Keith Thompson (The_Other_Keith) Keith.S.T...@gmail.com
Working, but not speaking, for Philips Healthcare
void Void(void) { Void(); } /* The recursive call of the void */

Richard Damon

unread,
Sep 12, 2020, 6:42:45 PM9/12/20
to
On 9/12/20 6:00 PM, Keith Thompson wrote:
> Richard Damon <Ric...@Damon-Family.org> writes:
> [...]
>> Another thing to consider is that despite what clause says, there are
>> implied "Fair Use" rights that people have, especially if the copyright
>> holder intentionally puts the document out on a public facing website.
>
> My limited understanding is that the Fair Use doctrine does not allow
> for distributing an entire work. Please don't take my work for this.
>
> "Fair Use" seems to be a widely misunderstood concept. I suggest that
> doing your own research or seeking out a forum where it's topical would
> be more productive that trying to discuss it here.
>

Yes, so by Fair use you can download and use if for yourself. If you
want to give it to someone else, you give them the link to the ISO site
and they can download it themselves.

Note, the assumption is that placing the file on their server with a
link that if you click on it will download the file to your computer
implies that you give permission for people to down load it to their
computer.

olcott

unread,
Sep 12, 2020, 7:34:08 PM9/12/20
to
On 9/12/2020 5:00 PM, Keith Thompson wrote:
> Richard Damon <Ric...@Damon-Family.org> writes:
> [...]
>> Another thing to consider is that despite what clause says, there are
>> implied "Fair Use" rights that people have, especially if the copyright
>> holder intentionally puts the document out on a public facing website.
>
> My limited understanding is that the Fair Use doctrine does not allow
> for distributing an entire work. Please don't take my work for this.
>
> "Fair Use" seems to be a widely misunderstood concept. I suggest that
> doing your own research or seeking out a forum where it's topical would
> be more productive that trying to discuss it here.
>

Fair Use varies across jurisdictions. For example Germany is a little
more restrictive than the USA.

Keith Thompson

unread,
Sep 12, 2020, 7:36:10 PM9/12/20
to
Richard Damon <Ric...@Damon-Family.org> writes:
> On 9/12/20 6:00 PM, Keith Thompson wrote:
>> Richard Damon <Ric...@Damon-Family.org> writes:
>> [...]
>>> Another thing to consider is that despite what clause says, there are
>>> implied "Fair Use" rights that people have, especially if the copyright
>>> holder intentionally puts the document out on a public facing website.
>>
>> My limited understanding is that the Fair Use doctrine does not allow
>> for distributing an entire work. Please don't take my work for this.
>>
>> "Fair Use" seems to be a widely misunderstood concept. I suggest that
>> doing your own research or seeking out a forum where it's topical would
>> be more productive that trying to discuss it here.
>
> Yes, so by Fair use you can download and use if for yourself. If you
> want to give it to someone else, you give them the link to the ISO site
> and they can download it themselves.

That is not consistent with my limited understanding of what "Fair Use"
actually means.

> Note, the assumption is that placing the file on their server with a
> link that if you click on it will download the file to your computer
> implies that you give permission for people to down load it to their
> computer.

I agree that that's a reasonable assumption. I don't know how or
whether that assumption is supported legally I would assume that, given
the huge number of files that have been publicly shared on the Internet,
there is ample legal precedent, but I have no idea what that precedent
says.

Tim Rentsch

unread,
Sep 12, 2020, 9:58:27 PM9/12/20
to
Juha Nieminen <nos...@thanks.invalid> writes:

> David Brown <david...@hesbynett.no> wrote:
>
>> One subset of VLA's that are safe, convenient and efficient are when the
>> size of the array is from a "const" variable that is known at compile time:
>>
>> void foo(void) {
>> const int sz = 100;
>> char vs[sz];
>> ...
>> }
>
> If I understand correctly 'const' integer variables in C aren't really
> considered compile-time constants (as they are in C++). Rather, 'const'
> is more like an instruction to the compiler that tells it "give me
> an error message at compile time if I ever try to assign something
> to this", but otherwise it's pretty much a "normal" variable.
>
> So I'm wondering what the C standard says about the above construct.
> Is the compiler allowed to assume that 'sz' is a compile-time constant
> and, thus, make 'vs' into a "regular" array (rather than a VLA)?

We might consider a case that does not involve a variable:

static int
one_hundred(void){
return 100;
}

void foo(void){
char vs[ one_hundred() ];
...
}

A compiler could easily deduce that the array dimension of vs
must be 100, and cannot vary. Despite that, the array vs is
a variable length array, and must be treated as such during
semantic processing in the compiler.

When it comes time to generate code, there is nothing stopping
the implementation from treating the variable vs as if it were
declared 'char vs[100];' and producing code accordingly, but
for the purpose of program semantics vs is a VLA. The same
statement applies in the earlier version of foo(), and also
in this version:

void foo(void) {
int sz = 100;
char vs[sz];
...
}

In each of these cases 'vs' must be treated as a VLA, but
may have code generated as if it were 'char vs[100];'.

Tim Rentsch

unread,
Sep 12, 2020, 10:31:51 PM9/12/20
to
Richard Damon <Ric...@Damon-Family.org> writes:

> On 9/10/20 6:31 AM, Juha Nieminen wrote:
>
>> David Brown <david...@hesbynett.no> wrote:
>>
>>> One subset of VLA's that are safe, convenient and efficient are when the
>>> size of the array is from a "const" variable that is known at compile time:
>>>
>>> void foo(void) {
>>> const int sz = 100;
>>> char vs[sz];
>>> ...
>>> }
>>
>> If I understand correctly 'const' integer variables in C aren't really
>> considered compile-time constants (as they are in C++). Rather, 'const'
>> is more like an instruction to the compiler that tells it "give me
>> an error message at compile time if I ever try to assign something
>> to this", but otherwise it's pretty much a "normal" variable.
>>
>> So I'm wondering what the C standard says about the above construct.
>> Is the compiler allowed to assume that 'sz' is a compile-time constant
>> and, thus, make 'vs' into a "regular" array (rather than a VLA)?
>>
>> (I suppose that the standard does give this permission if it says
>> something along the lines of "modifying a variable declared as const
>> is UB", which essentially tells the compiler "you can assume its
>> value is what you see, it won't ever change".)
>
> The compiler, via the 'as if' rule, can treat it like a fixed size
> array. Only is cases where the difference makes a difference would it
> need to treat it different.
>
> For instance &vs does NOT match the type of a pointer to char[100], but
> only to a pointer to char[sz]

The last statement is misleading. The two types aren't the same
but they are compatible, and can be used mostly interchangeably.
Example:

int
whee_ha( void ){
int k = 100;
char a[ 100 ];
char vla[ k ];
return &a == &vla;
}

This code must be accepted in C99. In particular, comparing the
two pointer values is allowed, and has defined behavior. If the
value of 'k' were, say, 97 instead of 100, then the two types are
still compatible, and thus no constraints are violated (so it
should compile cleanly); actually calling the function gives
rise to undefined behavior (because 97 != 100), but if the
function is never called then there isn't anything wrong with it
(meaning it could be part of a strictly conforming program).

Tim Rentsch

unread,
Sep 13, 2020, 12:07:20 PM9/13/20
to
Chris Vine <chris@cvine--nospam--.freeserve.co.uk> writes:

[...concerning the question of undefined behavior
of treating malloc'ed memory as an array ...]

> The closest to C++20 was N4849. Stimulated by David Brown I have now
> got hold of N4860. Assuming that that actually represents the final
> version of C++20 put to international ballot, it has considerable
> changes voted in at the last moment, probably in answer to
> http://wg21.link/p0593r6 , which pointed out the considerable
> deficiencies in C++17 and in the then draft standard respecting
> trivial objects.
>
> If so, that is surprising, as P0593r6 said:
>
> "This paper did not complete LWG review in time for C++20. However,
> the functionality contained herein can be split into two portions:
>
> The core language change that gives defined behavior to various
> constructs that have historically been assumed to work, and
>
> ...
>
> The author suggests that the committee considers adopting the former
> portion of this paper as a Defect Report, for possible inclusion into
> the C++20 IS, and that the latter portion be deferred to C++23."
>
> Maybe N4860 is C++20 plus defect report but it looks like the final
> version. No doubt in due course all will be revealed.

The impression I got from the quoted section there is that the
authors wanted it to be treated as a defect rather than a change,
and so meant to apply retroactively to C++17 (ie, after approval).
Does anyone have more context to offer on this notion?

David Brown

unread,
Sep 13, 2020, 4:20:18 PM9/13/20
to
On 13/09/2020 00:00, Keith Thompson wrote:
> Richard Damon <Ric...@Damon-Family.org> writes:
> [...]
>> Another thing to consider is that despite what clause says, there are
>> implied "Fair Use" rights that people have, especially if the copyright
>> holder intentionally puts the document out on a public facing website.
>
> My limited understanding is that the Fair Use doctrine does not allow
> for distributing an entire work. Please don't take my work for this.
>
> "Fair Use" seems to be a widely misunderstood concept. I suggest that
> doing your own research or seeking out a forum where it's topical would
> be more productive that trying to discuss it here.
>

I believe you are correct in this (both about the limitations you think
"fair use" has, and that it is a widely misunderstood concept). In
particular, "fair use" does /not/ mean "something that the copyright
holder appears to imply because of how they publish the work". When the
copyright owner puts a document on a public server, and says "here is
the latest draft document", you can well argue that you have an implied
licence to read it, save copies, pass them around, print them out, quote
them, etc. But that is an implied or assumed license, not "fair use".

Actual "fair use" varies a lot between jurisdictions (as with all this
kind of thing), and not all jurisdictions have the concept at all.
Typically it includes making quotations as part of a review, making
parodies, and that kind of thing.

(And don't take /my/ word for this either!)

James Kuyper

unread,
Sep 14, 2020, 12:16:51 AM9/14/20
to
On 9/11/20 2:57 PM, Chris Vine wrote:
> On Fri, 11 Sep 2020 11:44:54 -0400
> James Kuyper <james...@alumni.caltech.edu> wrote:
>> On 9/11/20 6:17 AM, Chris Vine wrote:
...
>> Do you mean "second example"? Tracing back, only the second example
>> involve pointer arithmentic (i++).
>> That is just as much a problem with C as with C++. For pointer values,
>> they both define i++ as equivalent to i=i+1, except that 'i' is
>> evaluated only once, and they both define addition of integer values to
>> pointer values in terms of a containing array; if there's no such array,
>> there's no applicable definition of what the addition means.
>
> Yes I did mean the second example. The point about C11 is that
> �6.5.6/8 deals with pointer arithmetic concerning arrays and the words
> "otherwise, the behavior is undefined" seem to have been read in the
> context of arrays only and not applying to raw malloc'ed memory. That
> reading is impossible with C++20's [expr.add]/4. ...

I don't see that as being the case. It says:
"When an expression J that has integral type is added to or subtracted
from an expression P of pointer type, the result has the type of P.
(4.1) — If P evaluates to a null pointer value and J evaluates to 0, the
result is a null pointer value.
(4.2) — Otherwise, if P points to an array element i of an array object
x with n elements (9.3.3.4), 76 the expressions P + J and J + P (where J
has the value j) point to the (possibly-hypothetical) array element i +
j of x if 0 ≤ i + j ≤ n and the expression P - J points to the
(possibly-hypothetical) array element i − j of x if 0 ≤ i − j ≤ n.
(4.3) — Otherwise, the behavior is undefined." (7.6.6p4).

Just like the corresponding words in the C standard, paragraph 4.2 is
predicated on P pointing at the i'th member of an array. If there is no
such array, then 4.3 applies, and the behavior is undefined.
If C++2020 handles this issue better than C does, the different wording
that makes that true must lie in some other part of the document.

> ... The issue with C is
> also that the "effective type" of raw memory is normally the type of
> the first object constructed in it (�6.5/6 of C11), so in a sense
> malloc'ed memory becomes an array in C by being treated as an array.

The fact that this isn't normally the case is precisely what's
problematic in C. When an lvalue of a given type is used to write to
dynamically allocated memory, that write gives that memory the effective
type of that lvalue. If you only write one element of an array at a
time, each element of that array acquires an effective type which is the
array's element type, but nothing acquires an effective type that is the
array type.
There are ways around this: you can write an entire struct object to the
memory using a single assignment expression, in which case that object
acquires that struct type as its effective type, and in particular, if
one of the members is an array, that member's memory acquires that array
type.
Also, when you copy an object into dynamically allocated memory using
memcpy(), memmove(), or otherwise copied as an array of character type,
there's a special rule that says that the memory acquires the effective
type of that object. As a special case of this, an array object can be
copied into the memory, giving it an array type.
Lots of C code treats dynamically allocated memory as if it were an
array, without either of those two special cases applying. Therefore, a
strict reading of the rules of pointer arithmetic gives access to any
element of such an array other than the first element undefined behavior.

> (Somewhat akin to the new C++ implicit-lifetime types.)

6.7.2p12 has code that contains a comment indicating that

X *p = (X*)std::malloc(sizeof(struct X))

implicitly creates an object of type X in the allocated memory.
20.10.12p5 appears to be the clause that actually supports that comment.
However, it's not clear to me from 20.10.12p5 that

X *p = (X*)std::malloc(n*sizeof(struct X));

would implicitly create an n-element array. I certainly wouldn't object
to that being the case, but it doesn't clearly say so.

> At any rate I doubt you will find any C programmer, or member of the C
> standard committee, who thinks that:
>
> int* i = (int*) malloc(2 * sizeof(int));
> i++;
>
> is undefined behaviour because of �6.5.6/8, as in C it is the only way
> of getting to the second element in advance of constructing the first
> one.

I think it is undefined behavior. I don't think it was intended to be
undefined behavior, so this represents a defect in the standard, but I
don't see any way to justify saying that there's an array that can be
used to give meaning to such pointer arithmetic.

> If N4860 is the definitive text for C++20, then I think this construct
> now has defined behaviour in C++20 because an array would implicitly be
> taken to arise for the case of an array of trivial types, given that
> array types are now implicit-lifetime types. I will need to consider
> revised [intro.object]/10 further on this.

Could you explain what that section says that makes you feel that way?

>>> ... You are right that an object that is not
>>> an array element whose address is taken by the unary & operator is
>>> considered to belong to an array with one element of type T for the
>>> purposes of pointer arithmetic on the value returned by that operator:
>>> in such a case you can add 1 to the address of the object.
>>>
>>> That doesn't apply here,
>>
>> In n3797.pdf, the relevant wording is "For the purposes of these
>> operators, a pointer to a nonarray object behaves the same as a pointer
>> to the first element of an array of length one with the type of the
>> object as its element type." (5.7p4), which seems perfectly applicable.
>> That wording does not include the part from your explanation requiring
>> that it be the result of the unary & operator; all that's required is
>> that it be "a pointer to a non-array object". How is the wording in
>> C++2020 different, to render that clause inapplicable?
>
> My meaning was that it was not applicable to my example, which did not
> involve construction of an object.

Now that I have a copy of n4860.pdf, I see that there's a much more
serious obstacle to having that clause apply: there is no such clause in
C++2020. The location in n4860.pdf that corresponds to 5.7 in n3797.pdf
is 7.6.6, but it contains no such wording, nor does similar wording
appear anywhere else. Given "int i;", is there no longer any meaning
defined for 1 + &i, or have I missed something that defines it? I've
just started reading this version of the standard - I wouldn't be
surprised if I missed something.

Ike Naar

unread,
Sep 14, 2020, 1:38:49 AM9/14/20
to
On 2020-09-11, James Kuyper <james...@alumni.caltech.edu> wrote:
> That is just as much a problem with C as with C++. For pointer values,
> they both define i++ as equivalent to i=i+1, except that 'i' is
> evaluated only once, and they both define addition of integer values to
> pointer values in terms of a containing array; if there's no such array,
> there's no applicable definition of what the addition means.

If "equivalent" means "identical in value", i++ and i=i+1 are not equivalent.
The value of i++ is the value of i before increment.
The value of i=i+1 is the value of i after increment.

James Kuyper

unread,
Sep 14, 2020, 9:38:23 AM9/14/20
to
I meant equivalent as a stand-alone expression, such as the one that was
being discussed. My purpose was to justify cross-referencing what both
standards say about adding integers to pointers, which is not described
directly in the paragraphs describing postfix increment; I wasn't
interested in going into the other aspects of that operator.

If I'd been inclined to discuss postfix increment operators in a more
general sense, the simplest way would have been to quote the entire
relevant paragraphs:

C:
"The result of the postfix ++ operator is the value of the operand. As a
side effect, the value of the operand object is incremented (that is,
the value 1 of the appropriate type is added to it). See the discussions
of additive operators and compound assignment for information on
constraints, types, and conversions and the effects of operations on
pointers. The value computation of the result is sequenced before the
side effect of updating the stored value of the operand. With respect to
an indeterminately-sequenced function call, the operation of postfix ++
is a single evaluation. Postfix ++ on an object with atomic type is a
read-modify-write operation with memory_order_seq_cst memory order
semantics."

C++:
"The value of a postfix ++ expression is the value of its operand.
[Note: The value obtained is a copy of the original value. — end note]
The operand shall be a modifiable lvalue. The type of the operand shall
be an arithmetic type other than cv bool, or a pointer to a complete
object type. An operand with volatile-qualified type is deprecated; see
D.5. The value of the operand object is modified (3.1) by adding 1 to
it. The value computation of the ++ expression is sequenced before the
modification of the operand object. With respect to an
indeterminately-sequenced function call, the operation of postfix ++ is
a single evaluation.
[Note: Therefore, a function call cannot intervene between the
lvalue-to-rvalue conversion and the side effect associated with any
single postfix ++ operator. — end note] The result is a prvalue. The
type of the result is the cv-unqualified version of the type of the
operand. If the operand is a bit-field that cannot represent the
incremented value, the resulting value of the bit-field is
implementation-defined."

Chris Vine

unread,
Sep 14, 2020, 8:59:19 PM9/14/20
to
On Mon, 14 Sep 2020 00:16:32 -0400
James Kuyper <james...@alumni.caltech.edu> wrote:
> On 9/11/20 2:57 PM, Chris Vine wrote:
> > The point about C11 is that
> > �6.5.6/8 deals with pointer arithmetic concerning arrays and the words
> > "otherwise, the behavior is undefined" seem to have been read in the
> > context of arrays only and not applying to raw malloc'ed memory. That
> > reading is impossible with C++20's [expr.add]/4. ...
>
> I don't see that as being the case. It says:
> "When an expression J that has integral type is added to or subtracted
> from an expression P of pointer type, the result has the type of P.
> (4.1) — If P evaluates to a null pointer value and J evaluates to 0, the
> result is a null pointer value.
> (4.2) — Otherwise, if P points to an array element i of an array object
> x with n elements (9.3.3.4), 76 the expressions P + J and J + P (where J
> has the value j) point to the (possibly-hypothetical) array element i +
> j of x if 0 ≤ i + j ≤ n and the expression P - J points to the
> (possibly-hypothetical) array element i − j of x if 0 ≤ i − j ≤ n.
> (4.3) — Otherwise, the behavior is undefined." (7.6.6p4).
>
> Just like the corresponding words in the C standard, paragraph 4.2 is
> predicated on P pointing at the i'th member of an array. If there is no
> such array, then 4.3 applies, and the behavior is undefined.
> If C++2020 handles this issue better than C does, the different wording
> that makes that true must lie in some other part of the document.

I don't agree as a matter of English that C++20's [expr.add]/4 has the
same effect as §6.5.6/8. Furthermore the C standard states of the C
allocation functions and arrays that "The pointer returned if the
allocation succeeds is suitably aligned so that it may be assigned to a
pointer to any type of object with a fundamental alignment requirement
and then used to access such an object or an array of such objects in
the space allocated (until the space is explicitly deallocated)". You
seem to be arguing that the only means of constructing such an array is
via memcpy() or memmove(). If so I disagree: things must be read in
context. Let's agree to disagree because I don't think this is worth
spending further time on.
See above on arrays. The wording isn't ideal but it just about does it
I think.

> > (Somewhat akin to the new C++ implicit-lifetime types.)
>
> 6.7.2p12 has code that contains a comment indicating that
>
> X *p = (X*)std::malloc(sizeof(struct X))
>
> implicitly creates an object of type X in the allocated memory.
> 20.10.12p5 appears to be the clause that actually supports that comment.
> However, it's not clear to me from 20.10.12p5 that
>
> X *p = (X*)std::malloc(n*sizeof(struct X));
>
> would implicitly create an n-element array. I certainly wouldn't object
> to that being the case, but it doesn't clearly say so.

On considering the standard further I think it does clearly say so once
you try to iterate over this memory by pointer arithmetic.
[basic.types]/9 says that all array types array types are
implicit-lifetime types. An implicit-lifetime type will automatically
be constructed in malloc'ed memory if doing so would result in the
program having defined behavior ([intro.object]/10 and [c.malloc]/4).
If you iterate a pointer over malloc'ed memory as if it were an array
then it becomes an array because that is necessary to give the program
defined behaviour. (As it happens that is also indisputably the
intention of p0593r6, and I think that intention has been achieved.)

> > At any rate I doubt you will find any C programmer, or member of the C
> > standard committee, who thinks that:
> >
> > int* i = (int*) malloc(2 * sizeof(int));
> > i++;
> >
> > is undefined behaviour because of �6.5.6/8, as in C it is the only way
> > of getting to the second element in advance of constructing the first
> > one.
>
> I think it is undefined behavior. I don't think it was intended to be
> undefined behavior, so this represents a defect in the standard, but I
> don't see any way to justify saying that there's an array that can be
> used to give meaning to such pointer arithmetic.

See above

> > If N4860 is the definitive text for C++20, then I think this construct
> > now has defined behaviour in C++20 because an array would implicitly be
> > taken to arise for the case of an array of trivial types, given that
> > array types are now implicit-lifetime types. I will need to consider
> > revised [intro.object]/10 further on this.
>
> Could you explain what that section says that makes you feel that way?

See above

> >>> ... You are right that an object that is not
> >>> an array element whose address is taken by the unary & operator is
> >>> considered to belong to an array with one element of type T for the
> >>> purposes of pointer arithmetic on the value returned by that operator:
> >>> in such a case you can add 1 to the address of the object.
> >>>
> >>> That doesn't apply here,
> >>
> >> In n3797.pdf, the relevant wording is "For the purposes of these
> >> operators, a pointer to a nonarray object behaves the same as a pointer
> >> to the first element of an array of length one with the type of the
> >> object as its element type." (5.7p4), which seems perfectly applicable.
> >> That wording does not include the part from your explanation requiring
> >> that it be the result of the unary & operator; all that's required is
> >> that it be "a pointer to a non-array object". How is the wording in
> >> C++2020 different, to render that clause inapplicable?
> >
> > My meaning was that it was not applicable to my example, which did not
> > involve construction of an object.
>
> Now that I have a copy of n4860.pdf, I see that there's a much more
> serious obstacle to having that clause apply: there is no such clause in
> C++2020. The location in n4860.pdf that corresponds to 5.7 in n3797.pdf
> is 7.6.6, but it contains no such wording, nor does similar wording
> appear anywhere else. Given "int i;", is there no longer any meaning
> defined for 1 + &i, or have I missed something that defines it? I've
> just started reading this version of the standard - I wouldn't be
> surprised if I missed something.

I have no idea what you mean. At any rate, I am pretty certain that
you have misunderstood what I meant. If you want to continue (and I am
not necessarily suggesting that you should, but do so if you would
like), can you start from the beginning again without reference to the
text of prior postings in a concise form.

Chris Vine

unread,
Sep 15, 2020, 5:25:00 AM9/15/20
to
On Tue, 15 Sep 2020 01:58:55 +0100
Chris Vine <chris@cvine--nospam--.freeserve.co.uk> wrote:
[snip]
> On considering the standard further I think it does clearly say so once
> you try to iterate over this memory by pointer arithmetic.
> [basic.types]/9 says that all array types array types are
> implicit-lifetime types. An implicit-lifetime type will automatically
> be constructed in malloc'ed memory if doing so would result in the
> program having defined behavior ([intro.object]/10 and [c.malloc]/4).
> If you iterate a pointer over malloc'ed memory as if it were an array
> then it becomes an array because that is necessary to give the program
> defined behaviour. (As it happens that is also indisputably the
> intention of p0593r6, and I think that intention has been achieved.)

By the way, please note that on my reading an array can come into
existence as an implicit-lifetime type without the array elements
coming into existence. That would have to be the case where the array
elements are not themselves implicit-lifetime types: they would need to
be constructed element by element by placement new (not placement
new[], which cannot reliably be used). The fact that there is an array
in existence means that you can iterate a pointer over the memory in
order to use placement new.

Of course, if the array elements are of implicit-lifetime type, then
they can be constructed by memcpy()/memmove() or by assignment.
Placement new is not necessary.
OK, I now see your point. You are pointing out that the text which says
that "For purposes of pointer arithmetic and comparison, an object that
is not an array element whose address is taken in this way is
considered to belong to an array with one element of type T" has been
removed in C++20. I hadn't noticed that.

That created a further problem with N4849. However, I don't think that
is an issue with N4860 because of the implied existence of an array.

James Kuyper

unread,
Sep 16, 2020, 9:58:21 AM9/16/20
to
I didn't say that they had the same effect - only that both descriptions
are "predicated on P pointing at the i'th member of an array". Both
descriptions become meaningless when that is not the case. If you
disagree, what would the value i be when there is no array? What would
the value of n be? What would be the meaning of "array element i+j"?

> ... Furthermore the C standard states of the C
> allocation functions and arrays that "The pointer returned if the
> allocation succeeds is suitably aligned so that it may be assigned to a
> pointer to any type of object with a fundamental alignment requirement
> and then used to access such an object or an array of such objects in
> the space allocated (until the space is explicitly deallocated)".

I'm sorry. I not only forgot about that clause, I forgot that I've
recently been reminded of that clause. After 62 years, my memory is not
what it used to be - and it was never exactly spectacular :-(. I retract
my claim that there's a problem in C.

...
>>>> In n3797.pdf, the relevant wording is "For the purposes of these
>>>> operators, a pointer to a nonarray object behaves the same as a pointer
>>>> to the first element of an array of length one with the type of the
>>>> object as its element type." (5.7p4), which seems perfectly applicable.
>>>> That wording does not include the part from your explanation requiring
>>>> that it be the result of the unary & operator; all that's required is
>>>> that it be "a pointer to a non-array object". How is the wording in
>>>> C++2020 different, to render that clause inapplicable?
>>>
>>> My meaning was that it was not applicable to my example, which did not
>>> involve construction of an object.
>>
>> Now that I have a copy of n4860.pdf, I see that there's a much more
>> serious obstacle to having that clause apply: there is no such clause in
>> C++2020. The location in n4860.pdf that corresponds to 5.7 in n3797.pdf
>> is 7.6.6, but it contains no such wording, nor does similar wording
>> appear anywhere else. Given "int i;", is there no longer any meaning
>> defined for 1 + &i, or have I missed something that defines it? I've
>> just started reading this version of the standard - I wouldn't be
>> surprised if I missed something.
>
> I have no idea what you mean. At any rate, I am pretty certain that
> you have misunderstood what I meant. If you want to continue (and I am
> not necessarily suggesting that you should, but do so if you would
> like), can you start from the beginning again without reference to the
> text of prior postings in a concise form.

OK - I'll try a different way of saying this.

1. In the C++ draft standard n3797.pdf, section 5.7 is about "Additive
Operators"

2. 5.7p4 says "For the purposes of these operators, a pointer to a
nonarray object behaves the same as a pointer to the first element of an
array of length one with the type of the object as its element type."

3. In the C++ draft standard n4860.pdf, the clauses have been
substantially rearranged, so the section covering "Additive operators"
is now 7.6.6.

4. Not only does n4860.pdf 7.6.6p4 not say the same thing that n3797.pdf
5.7p4 used to say, I can't find any equivalent wording anywhere else in
7.6.6, nor, for that matter, anywhere else in the standard. Now, if they
substantially changed the wording, my searches might have failed, so
it's entirely possible that it is there somewhere - but I don't know
where. If you do, please identify the clause.

If I'm correct that there is no wording in n4860.pdf that says basically
the same thing that was said in n3797.pdf 5.7p4, then that's a problem.
Here's why. Given the declaration:

int i;

In both C and C++, it was perfectly conforming behavior to pass &i and
1+&i to an algorithm that expects start and end pointers for an array of
objects. However,

5. The expression 1+&i has defined behavior in C only due to 6.5.6p7,
which says "For the purposes of these operators, a pointer to an object
that is not an element of an array behaves the same as a pointer to the
first element of an array of length one with the type of the object as
its element type." (which is essentially the same thing that n3937.pdf
says in 5.7p4 about C++).

6. If I'm right about there being no corresponding statement in
n4860.pdf, the latest draft of the C++ standard, then [expr.add]/4
becomes meaningless, because &i doesn't point at any element of any array.

7. The behavior of 1+&i is therefore undefined because "... this
document omits any explicit definition of behavior ..." (3.30).

Is that any clearer? If not, could you be more specific about what part
of that discussion you find unclear, and why? I've numbered parts of the
discussion for ease of reference.

Tim Rentsch

unread,
Sep 16, 2020, 10:20:18 AM9/16/20
to
James Kuyper <james...@alumni.caltech.edu> writes:

[...]

> OK - I'll try a different way of saying this.
>
> 1. In the C++ draft standard n3797.pdf, section 5.7 is about
> "Additive Operators"
>
> 2. 5.7p4 says "For the purposes of these operators, a pointer to a
> nonarray object behaves the same as a pointer to the first element
> of an array of length one with the type of the object as its element
> type."
>
> 3. In the C++ draft standard n4860.pdf, the clauses have been
> substantially rearranged, so the section covering "Additive
> operators" is now 7.6.6.
>
> 4. Not only does n4860.pdf 7.6.6p4 not say the same thing that
> n3797.pdf 5.7p4 used to say, I can't find any equivalent wording
> anywhere else in 7.6.6, nor, for that matter, anywhere else in the
> standard. [...]

Not to put too fine a point on it, did you try reading the
footnote referenced in 7.6.6p4?

James Kuyper

unread,
Sep 16, 2020, 10:53:21 AM9/16/20
to
On 9/16/20 9:57 AM, James Kuyper wrote:
...
> 2. 5.7p4 says "For the purposes of these operators, a pointer to a
> nonarray object behaves the same as a pointer to the first element of an
> array of length one with the type of the object as its element type."
...
> 5. The expression 1+&i has defined behavior in C only due to 6.5.6p7,
> which says "For the purposes of these operators, a pointer to an object
> that is not an element of an array behaves the same as a pointer to the
> first element of an array of length one with the type of the object as
> its element type." (which is essentially the same thing that n3937.pdf
> says in 5.7p4 about C++).
I just realized a key (and possibly unintentional) difference. Given:

    int myarray[5];

The object myarray is an array object, so C++ n3797.pdf 5.7p4 doesn't
apply to &myarray. However, myarray is not an element of an array, so C
6.5.6p7 does apply. That means that in C, &myarray is treated as if it
pointed at the first (and only) element of an array declared as
"int[1][5]", so 1+&myarray points one past the end of that notional 2D
array; but n3797.pdf doesn't allow that in C++. I doubt that this was
intentional, but since that wording has been removed in n4860.pdf, that
doesn't matter.

james...@alumni.caltech.edu

unread,
Sep 16, 2020, 1:28:59 PM9/16/20
to
On Wednesday, September 16, 2020 at 10:20:18 AM UTC-4, Tim Rentsch wrote:
> James Kuyper <james...@alumni.caltech.edu> writes:
...
> > 4. Not only does n4860.pdf 7.6.6p4 not say the same thing that
> > n3797.pdf 5.7p4 used to say, I can't find any equivalent wording
> > anywhere else in 7.6.6, nor, for that matter, anywhere else in the
> > standard. [...]

Thank you for snipping the part of my response admitting that my searches might have missed the relevant clause. I love being made to sound absolutely certain about something I've explicitly expressed doubts about.

> Not to put too fine a point on it, did you try reading the
> footnote referenced in 7.6.6p4?

No - the footnote reference displayed so small that I didn't notice it until the 6th time I checked it after you brought it to my attention, I didn't notice at all before you did so.
The reason my text searches didn't find it is that I was looking for the phrase "array of length one", which has been replaced by "single-element array".

james...@alumni.caltech.edu

unread,
Sep 16, 2020, 1:40:51 PM9/16/20
to
On Wednesday, September 16, 2020 at 10:53:21 AM UTC-4, james...@alumni.caltech.edu wrote:
...
> I just realized a key (and possibly unintentional) difference. Given:
>
> int myarray[5];
>
> The object myarray is an array object, so C++ n3797.pdf 5.7p4 doesn't
> apply to &myarray. However, myarray is not an element of an array, so C
> 6.5.6p7 does apply.

Thanks to TIm Rentsch for bringing to my attention that, in n4860.pdf, the normative text
has been moved to 6.8.2p3.2, and it now uses the same "not an element of an array" phrase
as the C standard, avoiding this problem and removing that difference.

Manfred

unread,
Oct 12, 2020, 12:54:04 PM10/12/20
to
The key words being "Unless otherwise specified"

Tim Rentsch

unread,
Dec 3, 2020, 10:48:11 PM12/3/20
to
"james...@alumni.caltech.edu" <james...@alumni.caltech.edu> writes:

> On Wednesday, September 16, 2020 at 10:20:18 AM UTC-4, Tim Rentsch wrote:
>
>> James Kuyper <james...@alumni.caltech.edu> writes:
>
> ...
>
>>> 4. Not only does n4860.pdf 7.6.6p4 not say the same thing that
>>> n3797.pdf 5.7p4 used to say, I can't find any equivalent wording
>>> anywhere else in 7.6.6, nor, for that matter, anywhere else in the
>>> standard. [...]
>
> Thank you for snipping the part of my response admitting that my
> searches might have missed the relevant clause. I love being made to
> sound absolutely certain about something I've explicitly expressed
> doubts about.

I assume you are being sarcastic.

I didn't include the statement that you might have missed
something because I wasn't responding to that part of your
posting. Besides, a statement that one may have missed something
seems rather superfluous, so including it seems redundant. I
didn't take it out to make you look dumb; I took it out because
it wasn't relevant to what I was saying, which is about where
to look to find the information desired. I'm sorry if it came
across as insulting, that was not my intention.

>> Not to put too fine a point on it, did you try reading the
>> footnote referenced in 7.6.6p4?
>
> No - the footnote reference displayed so small that I didn't notice
> it until the 6th time I checked it after you brought it to my
> attention, I didn't notice at all before you did so.
> The reason my text searches didn't find it is that I was looking for
> the phrase "array of length one", which has been replaced by
> "single-element array".

The people who have done the editing/writing/formatting for the
C++ standard have made a lot of decisions that make it harder to
read than it could be. One of those decisions is to use fonts
that are too small for the medium in which they appear. When I
read the C++ standard, I often crank up the magnification a step
or two to help with this problem. Another trick I use: when
looking at a particular page I (try to) always read the footnotes
on the page whether or not they look relevant to the passage I
was looking for. In the C++ standard in particular the side
material often contains useful information that is hard to find
in the main text, so "looking sideways" as it were in many cases
turns up something helpful or useful, even if not always directly
related to what is being sought at the moment.
0 new messages