Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c++ > #69217 > unrolled thread
| Started by | Frederick Gotham <cauldwell.thomas@gmail.com> |
|---|---|
| First post | 2019-10-15 03:00 -0700 |
| Last post | 2019-10-21 04:06 -0700 |
| Articles | 20 on this page of 51 — 18 participants |
Back to article view | Back to comp.lang.c++
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 →
| From | Frederick Gotham <cauldwell.thomas@gmail.com> |
|---|---|
| Date | 2019-10-15 03:00 -0700 |
| Subject | Which 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]
| From | melzzzzz <mel@melzzzzz.com> |
|---|---|
| Date | 2019-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]
| From | queequeg@trust.no1 (Queequeg) |
|---|---|
| Date | 2019-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]
| From | melzzzzz <mel@melzzzzz.com> |
|---|---|
| Date | 2019-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]
| From | Paavo Helde <myfirstname@osa.pri.ee> |
|---|---|
| Date | 2019-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]
| From | Frederick Gotham <cauldwell.thomas@gmail.com> |
|---|---|
| Date | 2019-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]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2019-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]
| From | Soviet_Mario <SovietMario@CCCP.MIR> |
|---|---|
| Date | 2019-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]
| From | scott@slp53.sl.home (Scott Lurndal) |
|---|---|
| Date | 2019-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]
| From | Soviet_Mario <SovietMario@CCCP.MIR> |
|---|---|
| Date | 2019-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]
| From | Paavo Helde <myfirstname@osa.pri.ee> |
|---|---|
| Date | 2019-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]
| From | Soviet_Mario <SovietMario@CCCP.MIR> |
|---|---|
| Date | 2019-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]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2019-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]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2019-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]
| From | Öö Tiib <ootiib@hot.ee> |
|---|---|
| Date | 2019-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]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2019-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]
| From | Soviet_Mario <SovietMario@CCCP.MIR> |
|---|---|
| Date | 2019-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]
| From | Öö Tiib <ootiib@hot.ee> |
|---|---|
| Date | 2019-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]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2019-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]
| From | Ian Collins <ian-news@hotmail.com> |
|---|---|
| Date | 2019-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