Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c++ > #69217 > unrolled thread

Which exception for a buffer overrun?

Started byFrederick Gotham <cauldwell.thomas@gmail.com>
First post2019-10-15 03:00 -0700
Last post2019-10-21 04:06 -0700
Articles 20 on this page of 51 — 18 participants

Back to article view | Back to comp.lang.c++


Contents

  Which exception for a buffer overrun? Frederick Gotham <cauldwell.thomas@gmail.com> - 2019-10-15 03:00 -0700
    Re:Which exception for a buffer overrun? melzzzzz <mel@melzzzzz.com> - 2019-10-15 12:52 +0200
      Re: Re:Which exception for a buffer overrun? queequeg@trust.no1 (Queequeg) - 2019-10-16 12:52 +0000
        Re: Re:Which exception for a buffer overrun? melzzzzz <mel@melzzzzz.com> - 2019-10-16 18:29 +0200
    Re: Which exception for a buffer overrun? Paavo Helde <myfirstname@osa.pri.ee> - 2019-10-15 13:54 +0300
      Re: Which exception for a buffer overrun? Frederick Gotham <cauldwell.thomas@gmail.com> - 2019-10-15 04:08 -0700
        Re: Which exception for a buffer overrun? David Brown <david.brown@hesbynett.no> - 2019-10-15 13:57 +0200
          Re: Which exception for a buffer overrun? Soviet_Mario <SovietMario@CCCP.MIR> - 2019-10-15 23:59 +0200
            Re: Which exception for a buffer overrun? scott@slp53.sl.home (Scott Lurndal) - 2019-10-15 22:13 +0000
              Re: Which exception for a buffer overrun? Soviet_Mario <SovietMario@CCCP.MIR> - 2019-10-16 15:04 +0200
            Re: Which exception for a buffer overrun? Paavo Helde <myfirstname@osa.pri.ee> - 2019-10-16 07:57 +0300
              Re: Which exception for a buffer overrun? Soviet_Mario <SovietMario@CCCP.MIR> - 2019-10-16 15:05 +0200
              Re: Which exception for a buffer overrun? Keith Thompson <kst-u@mib.org> - 2019-10-16 15:34 -0700
            Re: Which exception for a buffer overrun? David Brown <david.brown@hesbynett.no> - 2019-10-16 10:16 +0200
              Re: Which exception for a buffer overrun? Öö Tiib <ootiib@hot.ee> - 2019-10-16 05:54 -0700
                Re: Which exception for a buffer overrun? David Brown <david.brown@hesbynett.no> - 2019-10-16 16:12 +0200
                  Re: Which exception for a buffer overrun? Soviet_Mario <SovietMario@CCCP.MIR> - 2019-10-16 20:45 +0200
                  Re: Which exception for a buffer overrun? Öö Tiib <ootiib@hot.ee> - 2019-10-17 06:34 -0700
                    Re: Which exception for a buffer overrun? David Brown <david.brown@hesbynett.no> - 2019-10-17 16:34 +0200
              Re: Which exception for a buffer overrun? Ian Collins <ian-news@hotmail.com> - 2019-10-17 08:15 +1300
                Re: Which exception for a buffer overrun? David Brown <david.brown@hesbynett.no> - 2019-10-16 23:00 +0200
                  Re: Which exception for a buffer overrun? Ian Collins <ian-news@hotmail.com> - 2019-10-17 10:36 +1300
                    Re: Which exception for a buffer overrun? David Brown <david.brown@hesbynett.no> - 2019-10-17 10:14 +0200
                  Re: Which exception for a buffer overrun? Daniel <danielaparker@gmail.com> - 2019-10-16 20:06 -0700
              Re: Which exception for a buffer overrun? Bonita Montero <Bonita.Montero@gmail.com> - 2019-10-18 09:45 +0200
          Re: Which exception for a buffer overrun? Bonita Montero <Bonita.Montero@gmail.com> - 2019-10-17 21:22 +0200
        Re: Which exception for a buffer overrun? Paavo Helde <myfirstname@osa.pri.ee> - 2019-10-15 17:48 +0300
      Re: Which exception for a buffer overrun? "Fred. Zwarts" <F.Zwarts@KVI.nl> - 2019-10-15 13:09 +0200
        Re: Which exception for a buffer overrun? David Brown <david.brown@hesbynett.no> - 2019-10-15 13:35 +0200
          Re: Which exception for a buffer overrun? scott@slp53.sl.home (Scott Lurndal) - 2019-10-15 13:30 +0000
        Re: Which exception for a buffer overrun? melzzzzz <mel@melzzzzz.com> - 2019-10-15 13:49 +0200
          Re: Which exception for a buffer overrun? David Brown <david.brown@hesbynett.no> - 2019-10-15 13:59 +0200
        Re: Which exception for a buffer overrun? Jorgen Grahn <grahn+nntp@snipabacken.se> - 2019-10-15 14:48 +0000
          Re: Which exception for a buffer overrun? Paavo Helde <myfirstname@osa.pri.ee> - 2019-10-15 18:37 +0300
            Re: Which exception for a buffer overrun? melzzzzz <mel@melzzzzz.com> - 2019-10-15 18:48 +0200
        Re: Which exception for a buffer overrun? queequeg@trust.no1 (Queequeg) - 2019-10-16 13:00 +0000
      Re: Which exception for a buffer overrun? Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk> - 2019-10-15 18:21 +0100
        Re: Which exception for a buffer overrun? Melzzzzz <Melzzzzz@zzzzz.com> - 2019-10-15 20:32 +0000
          Re: Which exception for a buffer overrun? Jorgen Grahn <grahn+nntp@snipabacken.se> - 2019-10-16 06:20 +0000
      Re: Which exception for a buffer overrun? "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2019-10-16 14:43 -0700
    Re: Which exception for a buffer overrun? Jorgen Grahn <grahn+nntp@snipabacken.se> - 2019-10-15 11:12 +0000
    Re: Which exception for a buffer overrun? Öö Tiib <ootiib@hot.ee> - 2019-10-15 13:44 -0700
      Re: Which exception for a buffer overrun? Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk> - 2019-10-15 22:43 +0100
        Re: Which exception for a buffer overrun? Öö Tiib <ootiib@hot.ee> - 2019-10-16 00:01 -0700
          Re: Which exception for a buffer overrun? Jorgen Grahn <grahn+nntp@snipabacken.se> - 2019-10-16 19:02 +0000
            Re: Which exception for a buffer overrun? Öö Tiib <ootiib@hot.ee> - 2019-10-16 15:22 -0700
              Re: Which exception for a buffer overrun? Mike Terry <news.dead.person.stones@darjeeling.plus.com> - 2019-10-17 03:31 +0100
                Re: Which exception for a buffer overrun? Ian Collins <ian-news@hotmail.com> - 2019-10-17 15:35 +1300
                  Re: Which exception for a buffer overrun? David Brown <david.brown@hesbynett.no> - 2019-10-17 10:17 +0200
              Re: Which exception for a buffer overrun? Jorgen Grahn <grahn+nntp@snipabacken.se> - 2019-10-20 22:18 +0000
                Re: Which exception for a buffer overrun? Öö Tiib <ootiib@hot.ee> - 2019-10-21 04:06 -0700

Page 1 of 3  [1] 2 3  Next page →


#69217 — Which exception for a buffer overrun?

FromFrederick Gotham <cauldwell.thomas@gmail.com>
Date2019-10-15 03:00 -0700
SubjectWhich exception for a buffer overrun?
Message-ID<3cf9a0eb-088d-4c7f-903c-d0d40a9e1a8e@googlegroups.com>
Do you use out_of_range when there's a buffer overrun? It seems to be the closest

[toc] | [next] | [standalone]


#69218

Frommelzzzzz <mel@melzzzzz.com>
Date2019-10-15 12:52 +0200
Message-ID<qo48e5$qb5$1@news.albasani.net>
In reply to#69217

[Multipart message — attachments visible in raw view] — view raw

Frederick Gotham <cauldwell.thomas@gmail.com> Wrote in message:
> Do you use out_of_range when there's a buffer overrun? It seems to be the closest

I decided not to use exceptions in new programs... 
-- 
press any key to continue or any other to quit... 



----Android NewsGroup Reader----
http://usenet.sinaapp.com/

[toc] | [prev] | [next] | [standalone]


#69244

Fromqueequeg@trust.no1 (Queequeg)
Date2019-10-16 12:52 +0000
Message-ID<cc168922-ec97-439e-b94b-c76af75d5161@trust.no1>
In reply to#69218
melzzzzz <mel@melzzzzz.com> wrote:

>> Do you use out_of_range when there's a buffer overrun? It seems to be the closest
> 
> I decided not to use exceptions in new programs... 

What is the reason?

-- 
https://www.youtube.com/watch?v=9lSzL1DqQn0

[toc] | [prev] | [next] | [standalone]


#69252

Frommelzzzzz <mel@melzzzzz.com>
Date2019-10-16 18:29 +0200
Message-ID<qo7ghp$1jp$1@news.albasani.net>
In reply to#69244
queequeg@trust.no1 (Queequeg) Wrote in message:
> melzzzzz <mel@melzzzzz.com> wrote:>> Do you use out_of_range when there's a buffer overrun? It seems to be the closest> > I decided not to use exceptions in new programs... 

"What is the reason?" 

I started to use discriminated unions, as it is better way of
 handling errors... 
there was recent discussion about that... 
-- 
Press any key to continue or any other to quit.... 

[toc] | [prev] | [next] | [standalone]


#69219

FromPaavo Helde <myfirstname@osa.pri.ee>
Date2019-10-15 13:54 +0300
Message-ID<qo48hb$nfp$1@dont-email.me>
In reply to#69217
On 15.10.2019 13:00, Frederick Gotham wrote:
>
> Do you use out_of_range when there's a buffer overrun? It seems to be the closest

A buffer overrun should be considered a bug in the program and should be 
dealt with by abort() or similar, not by an exception. If an exception 
is thrown, it should be a "fatal" one, e.g. InternalFatalError, causing 
the error to be prominently logged/reported so it can be forwarded to 
the program maintainer for fixing, and the program terminated or at 
least returned the the main GUI/UI loop.

There is no point in throwing a special exception like out_of_range 
because the calling code has no way to fix its code to pass the correct 
index (if it could do that, it could have passed the correct index the 
first time).

If the calling code is just querying the length of an array or 
something, then this should never trigger exceptions. First, using 
exceptions for non-exceptional situations would convolute the program 
logic, and secondly it would be dead slow.

It's true that there is std::vector::at() which throws 
std::out_of_range, derived from std::logic_error, but many people 
consider the whole std::logic_error exception class hierarchy as an 
historical mistake.

[toc] | [prev] | [next] | [standalone]


#69220

FromFrederick Gotham <cauldwell.thomas@gmail.com>
Date2019-10-15 04:08 -0700
Message-ID<4aaa75f3-a489-49bd-89cf-356ece235d21@googlegroups.com>
In reply to#69219
On Tuesday, October 15, 2019 at 11:54:45 AM UTC+1, Paavo Helde wrote:

> A buffer overrun should be considered a bug in the program and should be 
> dealt with by abort() or similar, not by an exception.


So if I use a scissors to cut a slice of bread, am I abusing the scissors?

Are you one of those people who will only use something for the one specific use that it says on the box?

I'm curious what your stance is on exception throwing in recursive functions (instead of conditional return statements)?

[toc] | [prev] | [next] | [standalone]


#69225

FromDavid Brown <david.brown@hesbynett.no>
Date2019-10-15 13:57 +0200
Message-ID<qo4c7f$smj$1@dont-email.me>
In reply to#69220
On 15/10/2019 13:08, Frederick Gotham wrote:
> On Tuesday, October 15, 2019 at 11:54:45 AM UTC+1, Paavo Helde
> wrote:
> 
>> A buffer overrun should be considered a bug in the program and
>> should be dealt with by abort() or similar, not by an exception.
> 
> 
> So if I use a scissors to cut a slice of bread, am I abusing the
> scissors?

I'd say yes.  Aim to use the right tool for the job.  Use a poorer
choice of tool if you can't get the right tool, but only if there is no
option.

<https://www.youtube.com/watch?v=B84pS6JTI9A>

> 
> Are you one of those people who will only use something for the one
> specific use that it says on the box?

I can't answer for Paavo, but I am one of these people who try to think
out the best way to handle a task.

> 
> I'm curious what your stance is on exception throwing in recursive
> functions (instead of conditional return statements)?
> 

In C++, throwing an exception is usually /massively/ slower than
returning a code.  It can easily be thousands of times slower.  And for
recursive functions, it probably scales in time with the depth of the
recursion - and may limit optimisations of the functions.

Exceptions are fine when the situation is very rare and you don't have
requirements for worst-case latency, or where there is no sensible way
to handle the situation (like running out of memory), or when efficiency
doesn't matter and they make the code simpler and clearer (perhaps for
network or file errors).

They are a bad idea for normal processing as an alternative to return
values.

(The balance here will change significantly once static exceptions are
part of the language - they will be a great deal more efficient, and a
great deal easier for compile-time checking to support, at the cost of
less flexibility).

[toc] | [prev] | [next] | [standalone]


#69237

FromSoviet_Mario <SovietMario@CCCP.MIR>
Date2019-10-15 23:59 +0200
Message-ID<qo5ffc$fpe$1@dont-email.me>
In reply to#69225
On 15/10/2019 13:57, David Brown wrote:
> On 15/10/2019 13:08, Frederick Gotham wrote:
>> On Tuesday, October 15, 2019 at 11:54:45 AM UTC+1, Paavo Helde
>> wrote:
>>
>>> A buffer overrun should be considered a bug in the program and
>>> should be dealt with by abort() or similar, not by an exception.
>>
>>
>> So if I use a scissors to cut a slice of bread, am I abusing the
>> scissors?
> 
> I'd say yes.  Aim to use the right tool for the job.  Use a poorer
> choice of tool if you can't get the right tool, but only if there is no
> option.
> 
> <https://www.youtube.com/watch?v=B84pS6JTI9A>
> 
>>
>> Are you one of those people who will only use something for the one
>> specific use that it says on the box?
> 
> I can't answer for Paavo, but I am one of these people who try to think
> out the best way to handle a task.
> 
>>
>> I'm curious what your stance is on exception throwing in recursive
>> functions (instead of conditional return statements)?
>>
> 
> In C++, throwing an exception is usually /massively/ slower than
> returning a code.  It can easily be thousands of times slower.  And for
> recursive functions, it probably scales in time with the depth of the
> recursion - and may limit optimisations of the functions.
> 
> Exceptions are fine when the situation is very rare and you don't have
> requirements for worst-case latency, or where there is no sensible way
> to handle the situation (like running out of memory), or when efficiency
> doesn't matter and they make the code simpler and clearer (perhaps for
> network or file errors).
> 
> They are a bad idea for normal processing as an alternative to return
> values.
> 
> (The balance here will change significantly once static exceptions are
> part of the language - they will be a great deal more efficient, and a
> great deal easier for compile-time checking to support, at the cost of
> less flexibility).
> 


mine is just a no more than a hobbist tinkerer's opinion, 
but ...
even if I surely won't object to performance issues, another 
(often contrasting) point of view would be readability and 
cross-usability of code

I mean, often I feel the need of "consistent" (= UNIFORM) 
error management.

Even if surely more performant, mixed management can be 
difficult to understand and use.
So some importance maybe should also be given to the choice 
of using the same tool systematically for every problem of 
the same nature (errors), regardeless of its performance 
potential problems.
Also "snippet" reuse is hindered by mixed use of both 
exceptions and return types, and maybe it's more error prone.

One thing I really can't stand is the way C used to share a 
single variable (errno) to store status, that may be 
overwritten unpredictably




-- 
1) Resistere, resistere, resistere.
2) Se tutti pagano le tasse, le tasse le pagano tutti
Soviet_Mario - (aka Gatto_Vizzato)

[toc] | [prev] | [next] | [standalone]


#69238

Fromscott@slp53.sl.home (Scott Lurndal)
Date2019-10-15 22:13 +0000
Message-ID<9wrpF.30614$gT2.3004@fx19.iad>
In reply to#69237
Soviet_Mario <SovietMario@CCCP.MIR> writes:

>One thing I really can't stand is the way C used to share a 
>single variable (errno) to store status, that may be 
>overwritten unpredictably

Can you elaborate?   It was well understood and documented when errno could
be modified (on any system or library call).

[toc] | [prev] | [next] | [standalone]


#69247

FromSoviet_Mario <SovietMario@CCCP.MIR>
Date2019-10-16 15:04 +0200
Message-ID<qo74go$ca1$1@dont-email.me>
In reply to#69238
On 16/10/2019 00:13, Scott Lurndal wrote:
> Soviet_Mario <SovietMario@CCCP.MIR> writes:
> 
>> One thing I really can't stand is the way C used to share a
>> single variable (errno) to store status, that may be
>> overwritten unpredictably
> 
> Can you elaborate?   It was well understood and documented when errno could
> be modified (on any system or library call).
> 

I must have mis-expressed. Unpredictably would have meant 
that this variable can be async modified anywhere and 
anytime (and in multithread context, or even in event-driven 
programs, when a routine could be called amidst another call 
is working, and that gets frozen and revived later, one 
might find errno modified even just after tested in the last 
instruction on the "local" flow).

And in that case even knowing in advance this may happen is 
useless practically.
Sure : often this modification is not that relevant locally 
(an error occurred elsewhere is more likely not affect the 
reprise of the code frozen before) but not always.
Consider an error generated on a shared resource, like a 
file/stream and so.
Routine A tests a file (probing errno after some operation) 
before starting to worki and prepares to work on it

then an async event trigger invoke routine B (with A being 
put on wait) which generates an error on the same file, 
setting errno.
When resumed, routine A will assume wrongly that the file is 
not corrupted, but actually is.

Actually even return value test does not seem (to me) to 
protect much from this.
Exception is more resilient, at the cost of speed, as it 
catch on the fly ex-post rather then test-and-act)


-- 
1) Resistere, resistere, resistere.
2) Se tutti pagano le tasse, le tasse le pagano tutti
Soviet_Mario - (aka Gatto_Vizzato)

[toc] | [prev] | [next] | [standalone]


#69240

FromPaavo Helde <myfirstname@osa.pri.ee>
Date2019-10-16 07:57 +0300
Message-ID<qo6807$t60$1@dont-email.me>
In reply to#69237
On 16.10.2019 0:59, Soviet_Mario wrote:
> One thing I really can't stand is the way C used to share a single
> variable (errno) to store status, that may be overwritten unpredictably

It's not a single variable, it's a single variable per thread.

Yes, it may be overwritten by something seemingly innocent like a 
std::string construction, but this would be just "unexpectedly" (for 
some of us), not "unpredictably".

Errno may only be overwritten "unpredictably" if there is a signal 
handler which does not take care to store and restore it properly. But 
this would be a bug in the signal handler.

[toc] | [prev] | [next] | [standalone]


#69248

FromSoviet_Mario <SovietMario@CCCP.MIR>
Date2019-10-16 15:05 +0200
Message-ID<qo74je$caq$1@dont-email.me>
In reply to#69240
On 16/10/2019 06:57, Paavo Helde wrote:
> On 16.10.2019 0:59, Soviet_Mario wrote:
>> One thing I really can't stand is the way C used to share 
>> a single
>> variable (errno) to store status, that may be overwritten 
>> unpredictably
> 
> It's not a single variable, it's a single variable per thread.

oh ! Sorry I was wrong then :\

> 
> Yes, it may be overwritten by something seemingly innocent 
> like a std::string construction, but this would be just 
> "unexpectedly" (for some of us), not "unpredictably".
> 
> Errno may only be overwritten "unpredictably" if there is a 
> signal handler which does not take care to store and restore 
> it properly. But this would be a bug in the signal handler.

I have been in error :\

> 


-- 
1) Resistere, resistere, resistere.
2) Se tutti pagano le tasse, le tasse le pagano tutti
Soviet_Mario - (aka Gatto_Vizzato)

[toc] | [prev] | [next] | [standalone]


#69264

FromKeith Thompson <kst-u@mib.org>
Date2019-10-16 15:34 -0700
Message-ID<lna7a0fhf7.fsf@kst-u.example.com>
In reply to#69240
Paavo Helde <myfirstname@osa.pri.ee> writes:
> On 16.10.2019 0:59, Soviet_Mario wrote:
>> One thing I really can't stand is the way C used to share a single
>> variable (errno) to store status, that may be overwritten unpredictably
>
> It's not a single variable, it's a single variable per thread.

Right.  The standard says errno is a macro "which expands to a
modifiable lvalue that has type int and thread local storage duration,
the value of which is set to a positive error number by several library
functions".

On my system, the errno macro expands to
    (*__errno_location ())
where the __errno_location function presumably returns a pointer to a
thread-local int object.

This was introduced in C11.  In C90 and C99, thread local storage did
not exist, but implementations could do something equivalent.

-- 
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 */

[toc] | [prev] | [next] | [standalone]


#69243

FromDavid Brown <david.brown@hesbynett.no>
Date2019-10-16 10:16 +0200
Message-ID<qo6jls$hog$1@dont-email.me>
In reply to#69237
On 15/10/2019 23:59, Soviet_Mario wrote:
> On 15/10/2019 13:57, David Brown wrote:
>> On 15/10/2019 13:08, Frederick Gotham wrote:
>>> On Tuesday, October 15, 2019 at 11:54:45 AM UTC+1, Paavo Helde
>>> wrote:
>>>
>>>> A buffer overrun should be considered a bug in the program and
>>>> should be dealt with by abort() or similar, not by an exception.
>>>
>>>
>>> So if I use a scissors to cut a slice of bread, am I abusing the
>>> scissors?
>>
>> I'd say yes.  Aim to use the right tool for the job.  Use a poorer
>> choice of tool if you can't get the right tool, but only if there is no
>> option.
>>
>> <https://www.youtube.com/watch?v=B84pS6JTI9A>
>>
>>>
>>> Are you one of those people who will only use something for the one
>>> specific use that it says on the box?
>>
>> I can't answer for Paavo, but I am one of these people who try to think
>> out the best way to handle a task.
>>
>>>
>>> I'm curious what your stance is on exception throwing in recursive
>>> functions (instead of conditional return statements)?
>>>
>>
>> In C++, throwing an exception is usually /massively/ slower than
>> returning a code.  It can easily be thousands of times slower.  And for
>> recursive functions, it probably scales in time with the depth of the
>> recursion - and may limit optimisations of the functions.
>>
>> Exceptions are fine when the situation is very rare and you don't have
>> requirements for worst-case latency, or where there is no sensible way
>> to handle the situation (like running out of memory), or when efficiency
>> doesn't matter and they make the code simpler and clearer (perhaps for
>> network or file errors).
>>
>> They are a bad idea for normal processing as an alternative to return
>> values.
>>
>> (The balance here will change significantly once static exceptions are
>> part of the language - they will be a great deal more efficient, and a
>> great deal easier for compile-time checking to support, at the cost of
>> less flexibility).
>>
> 
> 
> mine is just a no more than a hobbist tinkerer's opinion, but ...
> even if I surely won't object to performance issues, another (often
> contrasting) point of view would be readability and cross-usability of code
> 

Readability is of course very important - and code correctness even more
so.  However, I am not convinced that exceptions are a great correctness
feature.  It is hard to write fully exception-safe code.  And, worse, it
is easy to write code that /appears/ to be exception safe, but is not.

The two key problems, as I see it, are first that exceptions means all
sorts of code (function calls and expressions) can fail unexpectedly at
any time, leading to early returns from your function.  You have to be
thinking all the time about what will happen if there is an exception
when the code runs.  This can mean making more RAII classes, or more
indirect references (via unique_ptr, for example), simply to ensure
cleanup in case functions throw an exception.  That will make the code
safe and correct - but can be of significant readability cost.

The other problem is that a lot of the information about C++ exceptions
that a function can throw, is basically lying.  You can /say/ that a
function only throws specific exception types, which would be very
useful, but it's a lie.  At least C++11 "noexcept" is a stronger, and
now "throw" specifications are no longer part of C++17 at all.  But
there is currently no way to say what exceptions a function really could
throw, no way to check such features at compile time, no integration
with the type system, and the default is for functions to be specified
as "this function could throw anything, or pass on any exception" rather
than the more sensible "this function won't throw - it will do what it
says it will do".

(Static exceptions will, hopefully, improve on this a lot.)

> I mean, often I feel the need of "consistent" (= UNIFORM) error
management.

Consistency is good - but not if it is artificial consistency just for
consistency's sake.

> 
> Even if surely more performant, mixed management can be difficult to
> understand and use.
> So some importance maybe should also be given to the choice of using the
> same tool systematically for every problem of the same nature (errors),
> regardeless of its performance potential problems.
> Also "snippet" reuse is hindered by mixed use of both exceptions and
> return types, and maybe it's more error prone.
> 
> One thing I really can't stand is the way C used to share a single
> variable (errno) to store status, that may be overwritten unpredictably
> 

Yes, errno is a very questionable idea.  It made sense when it was
introduced, but leads to many limitations.  It does allow some useful
practices, however, such as doing a string of calculations and then
checking for errno at the end rather than checking after each calculation.

(It's not a single global any more - there is one errno per thread.)

[toc] | [prev] | [next] | [standalone]


#69245

FromÖö Tiib <ootiib@hot.ee>
Date2019-10-16 05:54 -0700
Message-ID<2167dbb0-cff8-4f96-a29d-3da158520b17@googlegroups.com>
In reply to#69243
On Wednesday, 16 October 2019 11:17:13 UTC+3, David Brown  wrote:
> On 15/10/2019 23:59, Soviet_Mario wrote:
> > On 15/10/2019 13:57, David Brown wrote:
> >> On 15/10/2019 13:08, Frederick Gotham wrote:
> >>> On Tuesday, October 15, 2019 at 11:54:45 AM UTC+1, Paavo Helde
> >>> wrote:
> >>>
> >>>> A buffer overrun should be considered a bug in the program and
> >>>> should be dealt with by abort() or similar, not by an exception.
> >>>
> >>>
> >>> So if I use a scissors to cut a slice of bread, am I abusing the
> >>> scissors?
> >>
> >> I'd say yes.  Aim to use the right tool for the job.  Use a poorer
> >> choice of tool if you can't get the right tool, but only if there is no
> >> option.
> >>
> >> <https://www.youtube.com/watch?v=B84pS6JTI9A>
> >>
> >>>
> >>> Are you one of those people who will only use something for the one
> >>> specific use that it says on the box?
> >>
> >> I can't answer for Paavo, but I am one of these people who try to think
> >> out the best way to handle a task.
> >>
> >>>
> >>> I'm curious what your stance is on exception throwing in recursive
> >>> functions (instead of conditional return statements)?
> >>>
> >>
> >> In C++, throwing an exception is usually /massively/ slower than
> >> returning a code.  It can easily be thousands of times slower.  And for
> >> recursive functions, it probably scales in time with the depth of the
> >> recursion - and may limit optimisations of the functions.
> >>
> >> Exceptions are fine when the situation is very rare and you don't have
> >> requirements for worst-case latency, or where there is no sensible way
> >> to handle the situation (like running out of memory), or when efficiency
> >> doesn't matter and they make the code simpler and clearer (perhaps for
> >> network or file errors).
> >>
> >> They are a bad idea for normal processing as an alternative to return
> >> values.
> >>
> >> (The balance here will change significantly once static exceptions are
> >> part of the language - they will be a great deal more efficient, and a
> >> great deal easier for compile-time checking to support, at the cost of
> >> less flexibility).
> >>
> > 
> > 
> > mine is just a no more than a hobbist tinkerer's opinion, but ...
> > even if I surely won't object to performance issues, another (often
> > contrasting) point of view would be readability and cross-usability of code
> > 
> 
> Readability is of course very important - and code correctness even more
> so.  However, I am not convinced that exceptions are a great correctness
> feature.  It is hard to write fully exception-safe code.  And, worse, it
> is easy to write code that /appears/ to be exception safe, but is not.
> 
> The two key problems, as I see it, are first that exceptions means all
> sorts of code (function calls and expressions) can fail unexpectedly at
> any time, leading to early returns from your function.  You have to be
> thinking all the time about what will happen if there is an exception
> when the code runs.  This can mean making more RAII classes, or more
> indirect references (via unique_ptr, for example), simply to ensure
> cleanup in case functions throw an exception.  That will make the code
> safe and correct - but can be of significant readability cost.

Basically to live with exceptions all classes have to be RAII as bare
minimum. Yes, unique_ptr is one of the handy components for to
build (or on simpler case to typedef) such class but I don't 
understand what readability cost there is.  Can you bring example
what you meant?

> The other problem is that a lot of the information about C++ exceptions
> that a function can throw, is basically lying.  You can /say/ that a
> function only throws specific exception types, which would be very
> useful, but it's a lie.  At least C++11 "noexcept" is a stronger, and
> now "throw" specifications are no longer part of C++17 at all.  But
> there is currently no way to say what exceptions a function really could
> throw, no way to check such features at compile time, no integration
> with the type system, and the default is for functions to be specified
> as "this function could throw anything, or pass on any exception" rather
> than the more sensible "this function won't throw - it will do what it
> says it will do".

The exception specifications are often a lie anyway ... or hackable around.
What we see in lot of bad code of languages where basically everything
may throw? Something like that (Java or C#  code): 

    public void foo() throws Exception {/* ... */}  // WTF?

So there have to be tools and policies in place for to use the exceptions
regardless of language. However it is not in any way better with checking
error codes of function "success" returns. Latter just adds lot of 
required boilerplate code. Isn't that major readability cost? 

> (Static exceptions will, hopefully, improve on this a lot.)
> 
> > I mean, often I feel the need of "consistent" (= UNIFORM) error
> management.
> 
> Consistency is good - but not if it is artificial consistency just for
> consistency's sake.

Every good project has to establish consistent project-wide error
handling policy. It is likely possible to make it company-
wide when company is working on closely related products
in narrow problem domain. However I can not imagine  
programming-language-wide (or even industry-wide) error 
handling policies. May be with some different programming
language (like Rust).  

> 
> > 
> > Even if surely more performant, mixed management can be difficult to
> > understand and use.
> > So some importance maybe should also be given to the choice of using the
> > same tool systematically for every problem of the same nature (errors),
> > regardeless of its performance potential problems.
> > Also "snippet" reuse is hindered by mixed use of both exceptions and
> > return types, and maybe it's more error prone.
> > 
> > One thing I really can't stand is the way C used to share a single
> > variable (errno) to store status, that may be overwritten unpredictably
> > 
> 
> Yes, errno is a very questionable idea.  It made sense when it was
> introduced, but leads to many limitations.  It does allow some useful
> practices, however, such as doing a string of calculations and then
> checking for errno at the end rather than checking after each calculation.
> 
> (It's not a single global any more - there is one errno per thread.)

The errno is awful ... OTOH it seems to be the only semi-portable way 
in C++ to figure out what went wrong with lot of things (like with that
std::basic_fstream::open() and the like) when it matters. 

[toc] | [prev] | [next] | [standalone]


#69250

FromDavid Brown <david.brown@hesbynett.no>
Date2019-10-16 16:12 +0200
Message-ID<qo78ge$3ap$1@dont-email.me>
In reply to#69245
On 16/10/2019 14:54, Öö Tiib wrote:
> On Wednesday, 16 October 2019 11:17:13 UTC+3, David Brown  wrote:
>> On 15/10/2019 23:59, Soviet_Mario wrote:
>>> On 15/10/2019 13:57, David Brown wrote:

>>
>> Readability is of course very important - and code correctness even more
>> so.  However, I am not convinced that exceptions are a great correctness
>> feature.  It is hard to write fully exception-safe code.  And, worse, it
>> is easy to write code that /appears/ to be exception safe, but is not.
>>
>> The two key problems, as I see it, are first that exceptions means all
>> sorts of code (function calls and expressions) can fail unexpectedly at
>> any time, leading to early returns from your function.  You have to be
>> thinking all the time about what will happen if there is an exception
>> when the code runs.  This can mean making more RAII classes, or more
>> indirect references (via unique_ptr, for example), simply to ensure
>> cleanup in case functions throw an exception.  That will make the code
>> safe and correct - but can be of significant readability cost.
> 
> Basically to live with exceptions all classes have to be RAII as bare
> minimum. Yes, unique_ptr is one of the handy components for to
> build (or on simpler case to typedef) such class but I don't 
> understand what readability cost there is.  Can you bring example
> what you meant?
> 

I can try and give an outline of an example.  Suppose you have code like
this, using a bool "success" return instead of exceptions:

	bool success = tryThis();
	doThisAnyway();
	if (!success) return false;
	continueProcessing();
	return true;

How do you make that into an exception-based handling, with "tryThis"
throwing an exception on failure?

You can use a try block and re-throw:

	try {
		tryThis();
	} catch (...) {
		doThisAnyway();
		throw();
	}
	doThisAnyway();
	continueProcessing();

You've duplicated code as well as reducing the clarity.

Or you can make a class:

	struct DoThisAnyway_later {
		DoThisAnyway_later() {};
		~DoThisAnyway_later() { doThisAnyway(); };
	}

	{
		DoThisAnyway_later doThisAnywayLater();
		tryThis();
		// doThisAnyway called by destructor
	}
	continueProcessing();

Now you have re-arranged the order of the code, losing the correlation
between the textual order and the run-time order.  (A general "scope
guard" template would reduce the code here, but not change the re-ordering.)


With explicit, manual control of the errors or unusual circumstances, it
can be easier to see the flow of the code.

And note that if you want to be sure that "doThisAnyway()" is done, and
"tryThis()" does not have a "noexcept" specifier, you have to have
something like these exception-safe codings just in case, because it
/might/ throw something.  With a return-based solution, you know if it
is giving success feedback because it is in the return type (perhaps
something more sophisticated than a simple bool, such as a
std::optional, or a variant, or an "expected") - and you can mark it
with [[nodiscard]] to make sure the code checks the result.


I am not saying that exceptions /always/ make code harder to read - far
from it.  I am merely saying that /sometimes/ they do.

(To be clear here, my kind of C++ programming is usually done with
exception support disabled in the compiler - partly for worst-case
performance reasons, partly for clarity, partly due to limited support
for some targets, partly due to a mix of C and C++ code.  This limits my
experience of C++ exceptions.)

>> The other problem is that a lot of the information about C++ exceptions
>> that a function can throw, is basically lying.  You can /say/ that a
>> function only throws specific exception types, which would be very
>> useful, but it's a lie.  At least C++11 "noexcept" is a stronger, and
>> now "throw" specifications are no longer part of C++17 at all.  But
>> there is currently no way to say what exceptions a function really could
>> throw, no way to check such features at compile time, no integration
>> with the type system, and the default is for functions to be specified
>> as "this function could throw anything, or pass on any exception" rather
>> than the more sensible "this function won't throw - it will do what it
>> says it will do".
> 
> The exception specifications are often a lie anyway ... or hackable around.
> What we see in lot of bad code of languages where basically everything
> may throw? Something like that (Java or C#  code): 
> 
>     public void foo() throws Exception {/* ... */}  // WTF?
> 
> So there have to be tools and policies in place for to use the exceptions
> regardless of language. However it is not in any way better with checking
> error codes of function "success" returns. Latter just adds lot of 
> required boilerplate code. Isn't that major readability cost? 

Somewhere there is /always/ going to be a cost!

I think a lot of the readability cost of using function return values
for errors comes from the days of older C and older C compilers, where
you often had a mess of goto's in order to deal with errors underway
without having deeply nested "if" statements.  Often you can get a lot
clearer code by simply dividing the code into several smaller functions,
with a style of "if (!success) return false;" as an exit.  Before C99
"inline", and before compilers inlined single-use static functions
automatically, multiple small functions could quickly be costly in
efficiency.

And of course with C++ you have all the power of RAII, and tools like
std::unique_ptr - you don't need exceptions to use them.  They apply
equally well to exiting functions with an early return.

> 
>> (Static exceptions will, hopefully, improve on this a lot.)
>>
>>> I mean, often I feel the need of "consistent" (= UNIFORM) error
>> management.
>>
>> Consistency is good - but not if it is artificial consistency just for
>> consistency's sake.
> 
> Every good project has to establish consistent project-wide error
> handling policy. It is likely possible to make it company-
> wide when company is working on closely related products
> in narrow problem domain. However I can not imagine  
> programming-language-wide (or even industry-wide) error 
> handling policies. May be with some different programming
> language (like Rust).  
> 

Certainly there is no one "ideal for every case" solution here.

>>
>>>
>>> Even if surely more performant, mixed management can be difficult to
>>> understand and use.
>>> So some importance maybe should also be given to the choice of using the
>>> same tool systematically for every problem of the same nature (errors),
>>> regardeless of its performance potential problems.
>>> Also "snippet" reuse is hindered by mixed use of both exceptions and
>>> return types, and maybe it's more error prone.
>>>
>>> One thing I really can't stand is the way C used to share a single
>>> variable (errno) to store status, that may be overwritten unpredictably
>>>
>>
>> Yes, errno is a very questionable idea.  It made sense when it was
>> introduced, but leads to many limitations.  It does allow some useful
>> practices, however, such as doing a string of calculations and then
>> checking for errno at the end rather than checking after each calculation.
>>
>> (It's not a single global any more - there is one errno per thread.)
> 
> The errno is awful ... OTOH it seems to be the only semi-portable way 
> in C++ to figure out what went wrong with lot of things (like with that
> std::basic_fstream::open() and the like) when it matters. 
> 

I am not an errno fan myself.  But I can understand why it was made, and
that it could be useful for some kinds of coding.

[toc] | [prev] | [next] | [standalone]


#69254

FromSoviet_Mario <SovietMario@CCCP.MIR>
Date2019-10-16 20:45 +0200
Message-ID<qo7ofj$7og$1@dont-email.me>
In reply to#69250
On 16/10/2019 16:12, David Brown wrote:
> On 16/10/2019 14:54, Öö Tiib wrote:
>> On Wednesday, 16 October 2019 11:17:13 UTC+3, David Brown  wrote:
>>> On 15/10/2019 23:59, Soviet_Mario wrote:
>>>> On 15/10/2019 13:57, David Brown wrote:
> 
>>>
>>> Readability is of course very important - and code correctness even more
>>> so.  However, I am not convinced that exceptions are a great correctness
>>> feature.  It is hard to write fully exception-safe code.  And, worse, it
>>> is easy to write code that /appears/ to be exception safe, but is not.
>>>
>>> The two key problems, as I see it, are first that exceptions means all
>>> sorts of code (function calls and expressions) can fail unexpectedly at
>>> any time, leading to early returns from your function.  You have to be
>>> thinking all the time about what will happen if there is an exception
>>> when the code runs.  This can mean making more RAII classes, or more
>>> indirect references (via unique_ptr, for example), simply to ensure
>>> cleanup in case functions throw an exception.  That will make the code
>>> safe and correct - but can be of significant readability cost.
>>
>> Basically to live with exceptions all classes have to be RAII as bare
>> minimum. Yes, unique_ptr is one of the handy components for to
>> build (or on simpler case to typedef) such class but I don't
>> understand what readability cost there is.  Can you bring example
>> what you meant?
>>
> 
> I can try and give an outline of an example.  Suppose you have code like
> this, using a bool "success" return instead of exceptions:
> 
> 	bool success = tryThis();
> 	doThisAnyway();
> 	if (!success) return false;
> 	continueProcessing();
> 	return true;
> 
> How do you make that into an exception-based handling, with "tryThis"
> throwing an exception on failure?
> 
> You can use a try block and re-throw:
> 
> 	try {
> 		tryThis();
> 	} catch (...) {
> 		doThisAnyway();
> 		throw();
> 	}
> 	doThisAnyway();
> 	continueProcessing();
> 
> You've duplicated code as well as reducing the clarity.

the example is formally genial :)
But I wonder what could actually be inside.
I mean : a function like dothisanyway should be either 
independent on the execution of tryThis result, or, if it is 
just PARTIALLY dependent, then tryThis seems to have a too 
coarse grain : it has internally a part tryThis depends upon 
and another who don't, and it could be splitted logically in 
two function.
The former who is actually to be put BEFORE doThisAnyway, 
and the latter, possibly generating the error (on which 
doThisAnyway does not depend) who can be placed AFTER IT


getting sth like

tryThisPart_1 ();
doThisAnyway ();
try {
	tryThisPart_2 ();
} catch (...) {
  // etc
};

Part_1 is essential to doThisAnyway
Part_2 is independent

The two Parts seem to me to be logically weakly correlated 
... but it's just sort of an intuition, not really sure


> 
> Or you can make a class:
> 
> 	struct DoThisAnyway_later {
> 		DoThisAnyway_later() {};
> 		~DoThisAnyway_later() { doThisAnyway(); };
> 	}
> 
> 	{
> 		DoThisAnyway_later doThisAnywayLater();
> 		tryThis();
> 		// doThisAnyway called by destructor
> 	}
> 	continueProcessing();
> 
> Now you have re-arranged the order of the code, losing the correlation
> between the textual order and the run-time order.  (A general "scope
> guard" template would reduce the code here, but not change the re-ordering.)
> 
> 
> With explicit, manual control of the errors or unusual circumstances, it
> can be easier to see the flow of the code.
> 
> And note that if you want to be sure that "doThisAnyway()" is done, and
> "tryThis()" does not have a "noexcept" specifier, you have to have
> something like these exception-safe codings just in case, because it
> /might/ throw something.  With a return-based solution, you know if it
> is giving success feedback because it is in the return type (perhaps
> something more sophisticated than a simple bool, such as a
> std::optional, or a variant, or an "expected") - and you can mark it
> with [[nodiscard]] to make sure the code checks the result.
> 
> 
> I am not saying that exceptions /always/ make code harder to read - far
> from it.  I am merely saying that /sometimes/ they do.
> 
> (To be clear here, my kind of C++ programming is usually done with
> exception support disabled in the compiler - partly for worst-case
> performance reasons, partly for clarity, partly due to limited support
> for some targets, partly due to a mix of C and C++ code.  This limits my
> experience of C++ exceptions.)
> 
>>> The other problem is that a lot of the information about C++ exceptions
>>> that a function can throw, is basically lying.  You can /say/ that a
>>> function only throws specific exception types, which would be very
>>> useful, but it's a lie.  At least C++11 "noexcept" is a stronger, and
>>> now "throw" specifications are no longer part of C++17 at all.  But
>>> there is currently no way to say what exceptions a function really could
>>> throw, no way to check such features at compile time, no integration
>>> with the type system, and the default is for functions to be specified
>>> as "this function could throw anything, or pass on any exception" rather
>>> than the more sensible "this function won't throw - it will do what it
>>> says it will do".
>>
>> The exception specifications are often a lie anyway ... or hackable around.
>> What we see in lot of bad code of languages where basically everything
>> may throw? Something like that (Java or C#  code):
>>
>>      public void foo() throws Exception {/* ... */}  // WTF?
>>
>> So there have to be tools and policies in place for to use the exceptions
>> regardless of language. However it is not in any way better with checking
>> error codes of function "success" returns. Latter just adds lot of
>> required boilerplate code. Isn't that major readability cost?
> 
> Somewhere there is /always/ going to be a cost!
> 
> I think a lot of the readability cost of using function return values
> for errors comes from the days of older C and older C compilers, where
> you often had a mess of goto's in order to deal with errors underway
> without having deeply nested "if" statements.  Often you can get a lot
> clearer code by simply dividing the code into several smaller functions,
> with a style of "if (!success) return false;" as an exit.  Before C99
> "inline", and before compilers inlined single-use static functions
> automatically, multiple small functions could quickly be costly in
> efficiency.
> 
> And of course with C++ you have all the power of RAII, and tools like
> std::unique_ptr - you don't need exceptions to use them.  They apply
> equally well to exiting functions with an early return.
> 
>>
>>> (Static exceptions will, hopefully, improve on this a lot.)
>>>
>>>> I mean, often I feel the need of "consistent" (= UNIFORM) error
>>> management.
>>>
>>> Consistency is good - but not if it is artificial consistency just for
>>> consistency's sake.
>>
>> Every good project has to establish consistent project-wide error
>> handling policy. It is likely possible to make it company-
>> wide when company is working on closely related products
>> in narrow problem domain. However I can not imagine
>> programming-language-wide (or even industry-wide) error
>> handling policies. May be with some different programming
>> language (like Rust).
>>
> 
> Certainly there is no one "ideal for every case" solution here.
> 
>>>
>>>>
>>>> Even if surely more performant, mixed management can be difficult to
>>>> understand and use.
>>>> So some importance maybe should also be given to the choice of using the
>>>> same tool systematically for every problem of the same nature (errors),
>>>> regardeless of its performance potential problems.
>>>> Also "snippet" reuse is hindered by mixed use of both exceptions and
>>>> return types, and maybe it's more error prone.
>>>>
>>>> One thing I really can't stand is the way C used to share a single
>>>> variable (errno) to store status, that may be overwritten unpredictably
>>>>
>>>
>>> Yes, errno is a very questionable idea.  It made sense when it was
>>> introduced, but leads to many limitations.  It does allow some useful
>>> practices, however, such as doing a string of calculations and then
>>> checking for errno at the end rather than checking after each calculation.
>>>
>>> (It's not a single global any more - there is one errno per thread.)
>>
>> The errno is awful ... OTOH it seems to be the only semi-portable way
>> in C++ to figure out what went wrong with lot of things (like with that
>> std::basic_fstream::open() and the like) when it matters.
>>
> 
> I am not an errno fan myself.  But I can understand why it was made, and
> that it could be useful for some kinds of coding.
> 


-- 
1) Resistere, resistere, resistere.
2) Se tutti pagano le tasse, le tasse le pagano tutti
Soviet_Mario - (aka Gatto_Vizzato)

[toc] | [prev] | [next] | [standalone]


#69270

FromÖö Tiib <ootiib@hot.ee>
Date2019-10-17 06:34 -0700
Message-ID<ee417ec3-b9c9-4687-b3a8-b1dff5bc1242@googlegroups.com>
In reply to#69250
On Wednesday, 16 October 2019 17:12:40 UTC+3, David Brown  wrote:
> On 16/10/2019 14:54, Öö Tiib wrote:
> 
> I can try and give an outline of an example.  Suppose you have code like
> this, using a bool "success" return instead of exceptions:
> 
> 	bool success = tryThis();
> 	doThisAnyway();
> 	if (!success) return false;
> 	continueProcessing();
> 	return true;
> 
> How do you make that into an exception-based handling, with "tryThis"
> throwing an exception on failure?

Thanks. I will try to explain how I would approach it.  Not sure if my post
will show up though if there is some GG error. 

First, the doThisAnyway() feels a bit like some close/release/erase/reset
kind of clean-up-after-work function. It is preferable to bind those into
destructors together with RAII like one of your examples did. 

Also if the tryThis() is of "cleanup" kind (usually such calls are done
together) then it preferably should not throw in C++. Things that
may be called in destructors should indicate failures by other means
in C++ since standard library expects that destructors, operator
deletes and swaps don't throw.

If neither is cleanup function then it feels unusual. What it is that is
reasonable to do anyway regardless if previous steps failed? I can
live with duplicate code or with keeping the tryThis() non-throwing
or with making indeed some destructor-based "defer" for calling
doThisAnyway() but ... the whole situation feels interesting.

> With explicit, manual control of the errors or unusual circumstances, it
> can be easier to see the flow of the code.

It can make the actual algorithm harder to read. We need to add failed
state to all objects whose constructors or operators may fail. Checking
those is code. The actual reasons of failure are often abstracted
away by such "failed" state. A template can't be even expected
to know all failures that the objects it manipulates can face, so how
it can pass the information up intact? Exceptions are harder to
miss and can carry more information.

> I am not saying that exceptions /always/ make code harder to read - far
> from it.  I am merely saying that /sometimes/ they do.

There I agree, I have seen very lot of code that was made bad with 
exception handling. The reason is usually lack of skills, strategies
and policies. People should read the 31 suggestions from core
guidelines:
<http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#S-errors>
as minimum before using exceptions.

> (To be clear here, my kind of C++ programming is usually done with
> exception support disabled in the compiler - partly for worst-case
> performance reasons, partly for clarity, partly due to limited support
> for some targets, partly due to a mix of C and C++ code.  This limits my
> experience of C++ exceptions.)

I understand it so that in embedded development there it is usually
just not enough power to pass sophisticated error handling
information around and also the total number of possible fatal
failures is so low that each can have personalized bit for it
reserved in some int (or couple). 

> > So there have to be tools and policies in place for to use the exceptions
> > regardless of language. However it is not in any way better with checking
> > error codes of function "success" returns. Latter just adds lot of 
> > required boilerplate code. Isn't that major readability cost? 
> 
> Somewhere there is /always/ going to be a cost!
> 
> I think a lot of the readability cost of using function return values
> for errors comes from the days of older C and older C compilers, where
> you often had a mess of goto's in order to deal with errors underway
> without having deeply nested "if" statements.  Often you can get a lot
> clearer code by simply dividing the code into several smaller functions,
> with a style of "if (!success) return false;" as an exit.  Before C99
> "inline", and before compilers inlined single-use static functions
> automatically, multiple small functions could quickly be costly in
> efficiency.
> 
> And of course with C++ you have all the power of RAII, and tools like
> std::unique_ptr - you don't need exceptions to use them.  They apply
> equally well to exiting functions with an early return.

When failure means that caller has anyway not much to do
with more information then early false is fine and then the code
can be ok. However the error-handling policies often require
that way more information (potentially dynamic and structured)
is passed up about nature of failure.

[toc] | [prev] | [next] | [standalone]


#69271

FromDavid Brown <david.brown@hesbynett.no>
Date2019-10-17 16:34 +0200
Message-ID<qo9u5a$87a$1@dont-email.me>
In reply to#69270
On 17/10/2019 15:34, Öö Tiib wrote:
> On Wednesday, 16 October 2019 17:12:40 UTC+3, David Brown  wrote:
>> On 16/10/2019 14:54, Öö Tiib wrote:
>>
>> I can try and give an outline of an example.  Suppose you have code like
>> this, using a bool "success" return instead of exceptions:
>>
>> 	bool success = tryThis();
>> 	doThisAnyway();
>> 	if (!success) return false;
>> 	continueProcessing();
>> 	return true;
>>
>> How do you make that into an exception-based handling, with "tryThis"
>> throwing an exception on failure?
> 
> Thanks. I will try to explain how I would approach it.  Not sure if my post
> will show up though if there is some GG error. 
> 

It showed up for me, anyway.  And that's all that matters :-)

> First, the doThisAnyway() feels a bit like some close/release/erase/reset
> kind of clean-up-after-work function. It is preferable to bind those into
> destructors together with RAII like one of your examples did. 

If it is a pure cleanup, then RAII is likely to be the best way.  But
maybe it is not pure - perhaps it is using some data that is local in
the function, or maybe it is a debug/log function that you don't want to
be part of a "tryThis" object.  I am quite happy to accept that often
any kind of "doThisAnyway" code would naturally fit in an RAII
destructor - we are considering the situation where for some reason, it
is more natural, logical or maintainable to have it inside the main code.

> 
> Also if the tryThis() is of "cleanup" kind (usually such calls are done
> together) then it preferably should not throw in C++. Things that
> may be called in destructors should indicate failures by other means
> in C++ since standard library expects that destructors, operator
> deletes and swaps don't throw.
> 
> If neither is cleanup function then it feels unusual. What it is that is
> reasonable to do anyway regardless if previous steps failed?

Perhaps informing some other part of the system (or the user) of the
progress?

> I can
> live with duplicate code or with keeping the tryThis() non-throwing
> or with making indeed some destructor-based "defer" for calling
> doThisAnyway() but ... the whole situation feels interesting.

Yes, sometimes duplicate code is the simplest and clearest solution.

> 
>> With explicit, manual control of the errors or unusual circumstances, it
>> can be easier to see the flow of the code.
> 
> It can make the actual algorithm harder to read. We need to add failed
> state to all objects whose constructors or operators may fail. Checking
> those is code. The actual reasons of failure are often abstracted
> away by such "failed" state. A template can't be even expected
> to know all failures that the objects it manipulates can face, so how
> it can pass the information up intact? Exceptions are harder to
> miss and can carry more information.

A "success bool" carries all the information it needs (if a pass/fail
indication is all that is needed), and won't be missed.  Optionals,
variants, expecteds, are all other related solutions with more
flexibility.  And yes, templates /can/ be made to handle these.

> 
>> I am not saying that exceptions /always/ make code harder to read - far
>> from it.  I am merely saying that /sometimes/ they do.
> 
> There I agree, I have seen very lot of code that was made bad with 
> exception handling. The reason is usually lack of skills, strategies
> and policies. People should read the 31 suggestions from core
> guidelines:
> <http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#S-errors>
> as minimum before using exceptions.
> 
>> (To be clear here, my kind of C++ programming is usually done with
>> exception support disabled in the compiler - partly for worst-case
>> performance reasons, partly for clarity, partly due to limited support
>> for some targets, partly due to a mix of C and C++ code.  This limits my
>> experience of C++ exceptions.)
> 
> I understand it so that in embedded development there it is usually
> just not enough power to pass sophisticated error handling
> information around and also the total number of possible fatal
> failures is so low that each can have personalized bit for it
> reserved in some int (or couple). 

Yes.  Modern microcontrollers are often big enough and powerful enough
to handle exceptions, but supporting exceptions can be costly.  It
rarely matters on a PC if unwind tables adds 30% (taking a rough figure
out of the air) to the code space - probably it's still a drop in the
ocean compared to the graphics files and other non-code data in the
application, and your computer has almost unlimited disk space anyway.
30% bigger code space is a lot more significant when you have 256 KB of
flash.

There are many other reasons too.  Often in embedded systems, you are
concerned about worst-case performance - the last thing you want is a
code path that takes a long and unpredictable time.  You might not want
dynamic memory at all (or at least, you need to minimise it, or control
it with dedicated memory pools) - an exception system with unknown
numbers of exceptions floating around is not appropriate.  (Again,
static exceptions might fix this.)

And often you simply design your functions so that they cannot fail - if
failure is not an option, you don't need exceptions.

> 
>>> So there have to be tools and policies in place for to use the exceptions
>>> regardless of language. However it is not in any way better with checking
>>> error codes of function "success" returns. Latter just adds lot of 
>>> required boilerplate code. Isn't that major readability cost? 
>>
>> Somewhere there is /always/ going to be a cost!
>>
>> I think a lot of the readability cost of using function return values
>> for errors comes from the days of older C and older C compilers, where
>> you often had a mess of goto's in order to deal with errors underway
>> without having deeply nested "if" statements.  Often you can get a lot
>> clearer code by simply dividing the code into several smaller functions,
>> with a style of "if (!success) return false;" as an exit.  Before C99
>> "inline", and before compilers inlined single-use static functions
>> automatically, multiple small functions could quickly be costly in
>> efficiency.
>>
>> And of course with C++ you have all the power of RAII, and tools like
>> std::unique_ptr - you don't need exceptions to use them.  They apply
>> equally well to exiting functions with an early return.
> 
> When failure means that caller has anyway not much to do
> with more information then early false is fine and then the code
> can be ok. However the error-handling policies often require
> that way more information (potentially dynamic and structured)
> is passed up about nature of failure.
> 

[toc] | [prev] | [next] | [standalone]


#69256

FromIan Collins <ian-news@hotmail.com>
Date2019-10-17 08:15 +1300
Message-ID<h0p8ijF41nU1@mid.individual.net>
In reply to#69243
On 16/10/2019 21:16, David Brown wrote:
> On 15/10/2019 23:59, Soviet_Mario wrote:
>> On 15/10/2019 13:57, David Brown wrote:
>>> On 15/10/2019 13:08, Frederick Gotham wrote:
>>>> On Tuesday, October 15, 2019 at 11:54:45 AM UTC+1, Paavo Helde
>>>> wrote:
>>>>
>>>>> A buffer overrun should be considered a bug in the program and
>>>>> should be dealt with by abort() or similar, not by an exception.
>>>>
>>>>
>>>> So if I use a scissors to cut a slice of bread, am I abusing the
>>>> scissors?
>>>
>>> I'd say yes.  Aim to use the right tool for the job.  Use a poorer
>>> choice of tool if you can't get the right tool, but only if there is no
>>> option.
>>>
>>> <https://www.youtube.com/watch?v=B84pS6JTI9A>
>>>
>>>>
>>>> Are you one of those people who will only use something for the one
>>>> specific use that it says on the box?
>>>
>>> I can't answer for Paavo, but I am one of these people who try to think
>>> out the best way to handle a task.
>>>
>>>>
>>>> I'm curious what your stance is on exception throwing in recursive
>>>> functions (instead of conditional return statements)?
>>>>
>>>
>>> In C++, throwing an exception is usually /massively/ slower than
>>> returning a code.  It can easily be thousands of times slower.  And for
>>> recursive functions, it probably scales in time with the depth of the
>>> recursion - and may limit optimisations of the functions.
>>>
>>> Exceptions are fine when the situation is very rare and you don't have
>>> requirements for worst-case latency, or where there is no sensible way
>>> to handle the situation (like running out of memory), or when efficiency
>>> doesn't matter and they make the code simpler and clearer (perhaps for
>>> network or file errors).
>>>
>>> They are a bad idea for normal processing as an alternative to return
>>> values.
>>>
>>> (The balance here will change significantly once static exceptions are
>>> part of the language - they will be a great deal more efficient, and a
>>> great deal easier for compile-time checking to support, at the cost of
>>> less flexibility).
>>>
>>
>>
>> mine is just a no more than a hobbist tinkerer's opinion, but ...
>> even if I surely won't object to performance issues, another (often
>> contrasting) point of view would be readability and cross-usability of code
>>
> 
> Readability is of course very important - and code correctness even more
> so.  However, I am not convinced that exceptions are a great correctness
> feature.  It is hard to write fully exception-safe code.  And, worse, it
> is easy to write code that /appears/ to be exception safe, but is not.
> 
> The two key problems, as I see it, are first that exceptions means all
> sorts of code (function calls and expressions) can fail unexpectedly at
> any time, leading to early returns from your function.  You have to be
> thinking all the time about what will happen if there is an exception
> when the code runs.  This can mean making more RAII classes, or more
> indirect references (via unique_ptr, for example), simply to ensure
> cleanup in case functions throw an exception.  That will make the code
> safe and correct - but can be of significant readability cost.

The same set of conditions also apply to code that uses early returns. 
Throwing an exception is just a special case of an early return.

> The other problem is that a lot of the information about C++ exceptions
> that a function can throw, is basically lying.  You can /say/ that a
> function only throws specific exception types, which would be very
> useful, but it's a lie.  At least C++11 "noexcept" is a stronger, and
> now "throw" specifications are no longer part of C++17 at all.  But
> there is currently no way to say what exceptions a function really could
> throw, no way to check such features at compile time, no integration
> with the type system, and the default is for functions to be specified
> as "this function could throw anything, or pass on any exception" rather
> than the more sensible "this function won't throw - it will do what it
> says it will do".

This is true, but we are already there when we use the standard library 
unless we build with exceptions disabled.

-- 
Ian.

[toc] | [prev] | [next] | [standalone]


Page 1 of 3  [1] 2 3  Next page →

Back to top | Article view | comp.lang.c++


csiph-web