Saturday, June 15, 2019

Digest for comp.lang.c++@googlegroups.com - 23 updates in 4 topics

Real Troll <Real.Troll@Trolls.com>: Jun 15 04:55PM -0400

That religious nutter is gone so we can now start writing C++
programs!!!!!!!!!!!!!!!!!!!!!
 
<======================================================================>
#include <iostream>
#include <vector>
#include <string>
 
using namespace std;
 
int main()
{
 
vector<string> msg{"The",
"religious",
"nutter",
"is",
"gone",
"hooray!"};
 
for (const string& word : msg)
{
cout << word << " ";
}
cout << endl;
}
<======================================================================>
James Kuyper <jameskuyper@alumni.caltech.edu>: Jun 14 07:35PM -0400

On 6/14/19 8:44 AM, Juha Nieminen wrote:
 
> But what exactly happens if eg. your recursion level is too big and
> you run out of stack space?
 
> To be honest, I actually don't know what the standard says about this
 
Nothing. Almost all implementations of C++ use a stack structure to
store local variables, and many of them do so using a hardware stack,
but the standard says almost nothing about such issues.
 
The closest it comes to talking about such matters is to define the term
"implementation limits": "restrictions imposed upon programs by the
implementation". It takes some imagination to look at those words and
realize that a limited amount of stack space is one example of the kind
of limit it's talking about. The standard doesn't say anything about
what happens when you exceed an implementation limit, so the behavior is
undefined by "ommission of any explicit definition of the behavior".
 
It's all very vague and open to dispute. Have fun!
Ian Collins <ian-news@hotmail.com>: Jun 15 12:14PM +1200

On 15/06/2019 00:44, Juha Nieminen wrote:
 
> How exactly should programs be designed, if one wanted to be extra
> paranoid about the possibility of running out of stack space? Or is
> it something that there's simply no recourse against?
 
Don't use recursion, do use static analysis tools to check your stack depth!
 
--
Ian.
Ben Bacarisse <ben.usenet@bsb.me.uk>: Jun 15 02:25AM +0100

>> it something that there's simply no recourse against?
 
> Don't use recursion, do use static analysis tools to check your stack
> depth!
 
Recursion is not itself a problem. Tail call optimisation can eliminate
the stack costs for some recursive programs, and even without it, some
patterns of recursion are not inherently costly. For example, printing
a 32-bit number as a decimal by printing a tenth of it and the printing
the last digit won't recurse more than ten levels. Obviously, there are
limited environments where even that is unacceptable, but they are
probably the exception these days.
 
--
Ben.
Ian Collins <ian-news@hotmail.com>: Jun 15 01:30PM +1200

On 15/06/2019 13:25, Ben Bacarisse wrote:
> the last digit won't recurse more than ten levels. Obviously, there are
> limited environments where even that is unacceptable, but they are
> probably the exception these days.
 
Recursion may not be a problem, but it can defeat static analysis tools.
 
--
Ian.
Thiago Adams <thiago.adams@gmail.com>: Jun 14 07:20PM -0700

I don't known if any tool does that but
recursive functions could be reported with
a constant + number*N where N is how deep
we call the function.
Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Jun 15 09:59AM +0100

On Sat, 15 Jun 2019 02:25:34 +0100
> the last digit won't recurse more than ten levels. Obviously, there are
> limited environments where even that is unacceptable, but they are
> probably the exception these days.
 
What you say about tail call elimination is right for C, but not so
much for C++ because C++ has destructors, which means that most
recursive calls which look as if they are in tail position in fact
are not. To get tail call elimination to work in C++ you need to have
only built-in or trivial types (in other words, only C-like types) in
local scope when the recursive call is made.
 
That is one of the reasons why Rust has not implemented tail call
elimination despite it being heavily influenced by functional languages.
It has adopted C++'s approach of having determinative destruction/
deallocation of objects instead of garbage collection.
Melzzzzz <Melzzzzz@zzzzz.com>: Jun 15 10:02AM

> elimination despite it being heavily influenced by functional languages.
> It has adopted C++'s approach of having determinative destruction/
> deallocation of objects instead of garbage collection.
 
It had GC in the beginning, but they ditched it for performance reasons.
It also had segmented stack, which they also ditched for same reasons...
 
 
--
press any key to continue or any other to quit...
U ničemu ja ne uživam kao u svom statusu INVALIDA -- Zli Zec
Na divljem zapadu i nije bilo tako puno nasilja, upravo zato jer su svi
bili naoruzani. -- Mladen Gogala
Bonita Montero <Bonita.Montero@gmail.com>: Jun 15 01:59PM +0200

> But what exactly happens if eg. your recursion level is too big and
> you run out of stack space?
 
If you won't do massive alloca()s on most platforms there will never
be such a deep recursion-level that the stack.space is exhausted.
Consider that if you have thousands of recursion-levels you also will
have not only an according depth of the stack but also a with of the
recursions per node, i.e. your computations will last infinitely long.
David Brown <david.brown@hesbynett.no>: Jun 15 05:13PM +0200

On 14/06/2019 23:20, Alf P. Steinbach wrote:
 
> Then it was a misunderstanding of a machine that linked up stack frames
> obtained from a single contiguous machine stack.
 
> So a concrete link to the spec of "the mainframe" would be nice.
 
I don't know about mainframes, but I can tell you that gcc has support
for non-continguous stacks on various architectures. Spit stacks can be
particularly useful in multi-threaded code (since each thread needs its
own stack).
 
<https://gcc.gnu.org/wiki/SplitStacks>
 
(I haven't used this feature, nor can I say how common it is.)
 
>> on most systems, but there's no guarantee.  (And the stack could
>> grow either up or down.)
 
> Pointers to distinct objects can be compared using std::greater & family.
 
True (for C++14 onwards). They can also be compared, on most
architectures, by converting first to uintptr_t and comparing as integer
types. But they can't be compared with standard relational operators
unless the compiler documentation specifically says so. You can expect
older and simpler compilers to do such comparisons in the obvious way,
but newer tools are making more use of optimisations and re-arrangements
based on such operations being undefined. (This is precisely why newer
C++ additions, like std::greater, explicitly allow such comparisons - so
that you can get them if you need them.)
 
 
> On a segmented architecture one can imagine this being done by comparing
> first segment selectors, and if they're equal, the segment offsets.
 
You could imagine that, yes. But it would not match the physical
ordering of addresses in an architecture such as 16-bit x86.
 
David Brown <david.brown@hesbynett.no>: Jun 15 05:15PM +0200

On 14/06/2019 22:04, Thiago Adams wrote:
 
> What do you think about adding this one?
 
> If your hardware shares the memory between heap and stack:
 
> 10. Don't use dynamic memory allocation
 
Yes. On single-threaded embedded systems, it is common for the stack to
grow down from the top of memory, and the heap to grow upwards from top
of statically allocated data. You don't have to specify the sizes of
your heap and your stack, but bad things happen if they collide.
David Brown <david.brown@hesbynett.no>: Jun 15 05:18PM +0200

> to deal with again, unless your algorithm is broken.
 
> The only time I've gotten stack exceptions since the 1990s is
> when I've had an algorithm error.
 
The great majority of systems are not x86, and don't have any kind of
memory paging or virtual memory.
 
It is true that it is unlikely that you will have trouble running out of
stack space on a modern PC, unless you have some kind of runaway
recursion, but for other kinds of system it is a very relevant question.
David Brown <david.brown@hesbynett.no>: Jun 15 05:22PM +0200

On 15/06/2019 10:59, Chris Vine wrote:
> are not. To get tail call elimination to work in C++ you need to have
> only built-in or trivial types (in other words, only C-like types) in
> local scope when the recursive call is made.
 
A destructor is just a function invocation - which may be a call, or it
may be inlined. If the compiler can arrange the recursive calls with
tail call optimisations, it will - destructors are not any different
from any other code.
 
Paavo Helde <myfirstname@osa.pri.ee>: Jun 15 08:25PM +0300

On 15.06.2019 14:59, Bonita Montero wrote:
> Consider that if you have thousands of recursion-levels you also will
> have not only an according depth of the stack but also a with of the
> recursions per node, i.e. your computations will last infinitely long.
 
I wish that were true. With our script interpreter I can get a stack
overflow with just calculating factorial of 210 with a simple recursive
procedure. It implements recursion on real stack, from the debugger I
see that each script-level stack frame takes 4848 bytes and uses 5 C++
function call frames. The full C++ stack in the debugger is 1067 frames
deep and uses up 1MB (the default stack size in MSVC++).
 
Oh, and it takes just 0.15 seconds to get this stack overflow. There is
no alloca() and there are no special coding efforts spent on optimizing
the stack usage, in either direction.
 
Fortunately this script interpreter is not meant to be used for such
silly recursive procedures, so there is no urgent need to fix anything.
The relevant case has sit in the backlog over 10 years.
 
This example just shows that using such strong words like "never" and
"infinitely long" is not quite appropriate, one can get stack overflow
pretty easily. It's not a purely academic concern.
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Jun 15 08:34PM +0200

On 15.06.2019 17:13, David Brown wrote:
> own stack).
 
> <https://gcc.gnu.org/wiki/SplitStacks>
 
> (I haven't used this feature, nor can I say how common it is.)
 
It sounds challenging for debuggers. I wasn't aware of it. Thanks.
 
 
>>> grow either up or down.)
 
>> Pointers to distinct objects can be compared using std::greater & family.
 
> True (for C++14 onwards).
 
`std::greater` was there, providing a total ordering, in the first C++
standard, C++98. It's necessary for ordered containers of pointers.
 
I don't know if it was part of the de-facto standard library, as
specified by the ARM, in the pre-standard days.
 
I could check but that would involve either a lot of physical work
finding the book in a heap of boxes containing all kinds of stuff, or
semi-illegally downloading a PDF of the ARM.
 
 
>> offsets.
 
> You could imagine that, yes.  But it would not match the physical
> ordering of addresses in an architecture such as 16-bit x86.
 
I wouldn't call the original x86, with each physical memory address
belonging to (if my in-head arithmetic is correct) 4096 different
overlapping "segments", a segmented architecture. It was like a
receiver prepared for adaption to stereo, but not actually a stereo
receiver, in that it had registers and instructions that in a later
version, the 286, would be employed for segment handling. There were no
segment tables, just a simple arithmetic relationship (namely 16x)
between selector and physical segment start address.
 
 
>> single linear address space, or the possibility of doing that, that
>> doesn't imply that forming the difference of two such pointers is
>> necessarily possible on all platforms.
 
Cheers!,
 
- Alf
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Jun 15 08:41PM +0200

On 15.06.2019 17:22, David Brown wrote:
> may be inlined.  If the compiler can arrange the recursive calls with
> tail call optimisations, it will - destructors are not any different
> from any other code.
 
In the context of tail recursion a destructor is different, in that it's
invoked implicitly, not explicitly visible in the source code.
 
That can lead a non-expert programmer to believe tail recursion
optimization will be employed, when in fact it can't be (easily) employed.
 
Well there are other gotcha's also, e.g. that at least a decade ago
Visual C++ stubbornly refused to optimize tail recursion floating point
type results. So if one relies on tail recursion in C++ one should
better know what one is doing, and know one's compilers.
 
 
>> elimination despite it being heavily influenced by functional languages.
>> It has adopted C++'s approach of having determinative destruction/
>> deallocation of objects instead of garbage collection.
 
Interesting.
 
 
Cheers!,
 
- Alf
Keith Thompson <kst-u@mib.org>: Jun 15 01:03PM -0700

> On 14/06/2019 23:20, Alf P. Steinbach wrote:
>> On 14.06.2019 20:58, Keith Thompson wrote:
[...]
>>> grow either up or down.)
 
>> Pointers to distinct objects can be compared using std::greater & family.
 
> True (for C++14 onwards).
 
As Alf writes in a followup, std::greater has been in the
standard for a long time. There was a minor change in C++14.
https://en.cppreference.com/w/cpp/utility/functional/greater
 
> They can also be compared, on most
> architectures, by converting first to uintptr_t and comparing as
> integer types.
 
Yes, but that has even fewer guarantees than std::greater. If p and
q are pointers, you could have p==q but (uintptr_t)p != (uintptr_t)q
if p and q hold different representations of the same value.
 
std::greater guarantees a total ordering of pointer values, but
there's no guarantee that that ordering is meaningful. If you
compare addresses of three objects with automatic storage in the
order in which they're created, you'll *usually* get either
(&x < &y < &z) or (&x > &y > &z) (this is pseudo-code, not C++
notation), but all 6 orderings are legal.
 
(Since the built-in relational operators < <= > >= are undefined
on pointers to distinct objects, an implementation for a segmented
architecture can compare just the offsets, assuming each object
is in a single segment. == and != might have to do more work to
distinguish between pointers to different segments with the same
offset.)
 
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Will write code for food.
void Void(void) { Void(); } /* The recursive call of the void */
Robert Wessel <robertwessel2@yahoo.com>: Jun 15 12:58PM -0500

On Fri, 14 Jun 2019 08:31:33 -0400, James Kuyper
>on any system where FLT_RADIX is a multiple of 2 (the most common values
>are 2, 10, and 16 - I've never heard of a real system where it wasn't a
>multiple of 2), and on such systems 3.0/2.0 == 1.5.
 
 
FSVO "real". Ternary FP has existed on at least emulated (ternary)
systems.
 
https://en.wikipedia.org/wiki/Ternac
 
FP was implemented (in software, I believe) on the balanced ternary
Soviet Sutuns, but the exact format has never been clear to me (and
all of the documentation I've found is unhelpfully - at least to me -
in Russian), but ternary FP seems at least a plausible choice for
that.
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Jun 15 01:28AM +0100

On 14/06/2019 17:55, Rick C. Hodgin wrote:
> Ken Thompson demonstrating his evolutionary view of the necessity of
> forward declarations given modern CPU performance in compilation),
> consider it to be a wonderful thing.
 
And Satan invented fossils, yes?
 
/Flibble
 
--
"Snakes didn't evolve, instead talking snakes with legs changed into
snakes." - Rick C. Hodgin
 
"You won't burn in hell. But be nice anyway." – Ricky Gervais
 
"I see Atheists are fighting and killing each other again, over who
doesn't believe in any God the most. Oh, no..wait.. that never happens." –
Ricky Gervais
 
"Suppose it's all true, and you walk up to the pearly gates, and are
confronted by God," Bryne asked on his show The Meaning of Life. "What
will Stephen Fry say to him, her, or it?"
"I'd say, bone cancer in children? What's that about?" Fry replied.
"How dare you? How dare you create a world to which there is such misery
that is not our fault. It's not right, it's utterly, utterly evil."
"Why should I respect a capricious, mean-minded, stupid God who creates a
world that is so full of injustice and pain. That's what I would say."
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Jun 15 01:29AM +0100

On 14/06/2019 17:57, Rick C. Hodgin wrote:
> I had not intended to be on Usenet for C# programming.
 
> My interests in C/C++ have not changed, nor in CAlive.  I just won't
> be here reading on a regular basis.
 
Nobody cares.
 
/Flibble
 
--
"Snakes didn't evolve, instead talking snakes with legs changed into
snakes." - Rick C. Hodgin
 
"You won't burn in hell. But be nice anyway." – Ricky Gervais
 
"I see Atheists are fighting and killing each other again, over who
doesn't believe in any God the most. Oh, no..wait.. that never happens." –
Ricky Gervais
 
"Suppose it's all true, and you walk up to the pearly gates, and are
confronted by God," Bryne asked on his show The Meaning of Life. "What
will Stephen Fry say to him, her, or it?"
"I'd say, bone cancer in children? What's that about?" Fry replied.
"How dare you? How dare you create a world to which there is such misery
that is not our fault. It's not right, it's utterly, utterly evil."
"Why should I respect a capricious, mean-minded, stupid God who creates a
world that is so full of injustice and pain. That's what I would say."
David Brown <david.brown@hesbynett.no>: Jun 15 09:44AM +0200

On 14/06/2019 19:07, Bart wrote:
> use?
 
> I find lack of out-of-order declarations in C, to be a considerable
> pain. Although I think this mainly applies to functions.
 
As a Python user, I find being able to use things without declaring them
to be a major source of errors, so I would not like that to be possible.
As far as I can tell about C# (having read a small amount, but never
used it), you need to declare variables before using them.
 
Maybe functions can be used without declaring them first (as long as
they are declared later). That does not seem unreasonable to me. I am
not personally bothered that you need to declare functions before using
them in C, but I understand that it is an inconvenience to some people.
And I would rather that the language allowed calling functions before
they are declared than the mess some people write with long reams of
forward function declarations at the start of C files.
Bonita Montero <Bonita.Montero@gmail.com>: Jun 15 06:49PM +0200

>> You don't have to declare everything before you use it.
 
> Many people, including myself, consider that to be a bad thing.
 
With todays IDEs it's not a pain when there aren't any forward
-declarations. Just right-click at the symbol and click the
option to guide to the definition.
I like C++ but I don't think forward-declarations are an adantage.
Bart <bc@freeuk.com>: Jun 15 05:58PM +0100

On 15/06/2019 17:49, Bonita Montero wrote:
 
> With todays IDEs it's not a pain when there aren't any forward
> -declarations. Just right-click at the symbol and click the
> option to guide to the definition.
 
What good does that do? This is not about finding the definition. It is
having to ensure that when writing this (or copying it, moving it,
pasting it):
 
fn(a,b,c);
 
that either a definition or declaration of fn has been encountered prior
to this point.
 
> I like C++ but I don't think forward-declarations are an adantage.
 
It's a language issue. If the IDE does take care of it, it means it's
generating the necessary code, and also means you aren't strictly
writing in C or C++, but a version of it doesn't need you to explicitly
take care of such things.
 
If further means there there /is/ a need to deal with that nuisance.
You received this digest because you're subscribed to updates for this group. You can change your settings on the group membership page.
To unsubscribe from this group and stop receiving emails from it send an email to comp.lang.c+++unsubscribe@googlegroups.com.

No comments: