- Newfangled constructs - 16 Updates
- "Bjarne Stroustrup announces C++ Core Guidelines" - 2 Updates
- Basic exception handling. - 3 Updates
"Öö Tiib" <ootiib@hot.ee>: Nov 19 05:56PM -0800 On Friday, 20 November 2015 00:53:52 UTC+2, Ian Collins wrote: > > } > > catch(const NonLocalExit& e) {} > That's a terrible abuse of exceptions! +1 Misused exception (thrown and caught in same function) makes that code to look like garbage. Common case like "found" is clear example when *not* to use exceptions. Exceptions are for rare cases (that sometimes happen) like "corrupted", "too_full", "broken", "short_circuited", "timed_out", "unavailable", "underpowered" etc. The operation can not continue and so it breaks with exception thrown up stack. Typically it is caught far since there are nothing to do than to stop the whole feature. Exception is optimized to have close to no cost when it isn't thrown for being rather expensive when it is thrown. If normal or common condition is signaled with it then that can hurt performance in major way. |
Gareth Owen <gwowen@gmail.com>: Nov 20 07:03AM > I think it is. What would be clearer in the code flow, a nested loop > with a clunky exit mechanism or a call to an appropriately named > function? Well, that's exactly what I meant by "lesser of several evils". I happily accept that a function call may well be better than a nested loop with clunky exit mechanism, but it wouldn't necessarily be better than a nested loop with a much cleaner (entirely hypothetical) exit mechanism, with the exit condition stored in the loop construct. >> } >> catch(const NonLocalExit& e) {} > That's a terrible abuse of exceptions! They're just another language feature, and one that expresses the desired behaviour "jump out of the normal flow of control and resume at the end of the loop". It's a goto for people with a fear of 'goto'. Let the compiler sort out the exit strategy when it optimises the function! Would you consider it an abuse of exceptions if the (found) condition was something that almost never happened? |
Wouter van Ooijen <wouter@voti.nl>: Nov 20 08:07AM +0100 Op 20-Nov-15 om 2:56 AM schreef Öö Tiib: >> That's a terrible abuse of exceptions! > +1 Misused exception (thrown and caught in same function) makes that > code to look like garbage. Maybe to your eye, but not necesarily to mine. > "underpowered" etc. The operation can not continue and so it breaks > with exception thrown up stack. Typically it is caught far since there > are nothing to do than to stop the whole feature. BTW how do you know for sure that (found) is a common case? > for being rather expensive when it is thrown. If normal or common > condition is signaled with it then that can hurt performance in major > way. Which makes your opinion of how exceptions should be used an example of implementation-dependendt optimization. double yuk. I can accept arguments based on readablity, but I abhor premature optimization. Wouter |
Gareth Owen <gwowen@gmail.com>: Nov 20 07:26AM > of implementation-dependendt optimization. double yuk. > I can accept arguments based on readablity, but I abhor premature > optimization. I agree with Wouter. |
Ian Collins <ian-news@hotmail.com>: Nov 20 08:59PM +1300 Gareth Owen wrote: > loop with clunky exit mechanism, but it wouldn't necessarily be better > than a nested loop with a much cleaner (entirely hypothetical) exit > mechanism, with the exit condition stored in the loop construct. I would usually say it was. > Let the compiler sort out the exit strategy when it optimises the function! > Would you consider it an abuse of exceptions if the (found) condition > was something that almost never happened? Yes. -- Ian Collins |
David Brown <david.brown@hesbynett.no>: Nov 20 09:07AM +0100 On 20/11/15 02:56, 嘱 Tiib wrote: > for being rather expensive when it is thrown. If normal or common > condition is signaled with it then that can hurt performance in major > way. If the compiler knows all about a particular exception, since it is thrown and caught in the same function (and it can be sure that the exception cannot escape), then it is perfectly free to optimise such code into a "goto". I am not saying that such a use of exceptions is a good idea in general, merely that it is not necessarily as inefficient as you think. |
Juha Nieminen <nospam@thanks.invalid>: Nov 20 10:23AM > I'd almost prefer the goto. IMHO, breaking out of nested loops is > the only legitimate use of goto. No, it isn't. "Goto considered harmful" is not just a light quip. It's actually quite a useful principle. The correct way is to put the loop in its own function, and use 'return' there. If your code is such that doing so would be laborious and contrived, then that's a sign that you need a redesign. Carefully redesign your implementation in such a manner that putting the nested loop in its own function becomes natural, clean, understandable and efficient, and you will suddenly realize how much better your implementation has become overall (ie. not just for this particular nested loop.) Splitting larger functions into smaller ones, in a logical and structured manner, improves the quality and usability of your code. You don't need to go overboard with this, but once you start having a function with more than, say 20 or 30 lines of code, sit back and rethink what you are doing, and whether you could do it better. Doing it cleanly like that might positively surprise you later, when refactoring and enhancing the code becomes easier. --- news://freenews.netfront.net/ - complaints: news@netfront.net --- |
Juha Nieminen <nospam@thanks.invalid>: Nov 20 10:29AM > Unnecessary functional decomposition can often increase a program's > complexity Citation needed. It seems to me that this notion may well be based on prejudice, and/or perhaps not enough experience, rather than practice. (A bit like the notion that always using the std:: prefix makes the code more "unreadable".) When I have tried in a practical program to divide implementation into smaller logical functions, I have noticed that it actually improves the quality of the code. (For instance, in one case I had to make a specialization of a class, and it turned out to be a lot easier thanks to the fact that I had divided the base class' implementation into smaller logical functions, rather than use a few megafunctions.) Dividing a program into smaller functions doesn't *automatically* make the program better. Of course you need to put thought into it. However, when you do, you may find that your program just becomes better designed. If you can't easily isolate your nested loop into its own function, then perhaps that's a sign that your implementation is too complex and would benefit from a redesign and refactoring. --- news://freenews.netfront.net/ - complaints: news@netfront.net --- |
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Nov 20 05:23PM On 20/11/2015 10:29, Juha Nieminen wrote: >> Unnecessary functional decomposition can often increase a program's >> complexity > Citation needed. I am my own source mate. > It seems to me that this notion may well be based on prejudice, and/or > perhaps not enough experience, rather than practice. (A bit like the notion I've got 30+ years of experience to draw on when making such an assertion mate sausages. /Flibble |
"Öö Tiib" <ootiib@hot.ee>: Nov 20 09:42AM -0800 On Friday, 20 November 2015 09:07:31 UTC+2, Wouter van Ooijen wrote: > > +1 Misused exception (thrown and caught in same function) makes that > > code to look like garbage. > Maybe to your eye, but not necesarily to mine. Yes to my eye it clearly looks over-engineered bloat. Worthless object is created thrown and caught instead of just simply jumping out of cycle or returning out of function. > > with exception thrown up stack. Typically it is caught far since there > > are nothing to do than to stop the whole feature. > BTW how do you know for sure that (found) is a common case? To me finding what I search for has never been exceptional case. > > way. > Which makes your opinion of how exceptions should be used an example of > implementation-dependendt optimization. double yuk. Exceptions are optimized in that way to best support what these are made for. These are made for (, like name indicates,) handling exceptional situations. If exceptions are not made efficient for handling exceptional situations by particular implementation then that means that the implementation is of low quality. > I can accept arguments based on readablity, but I abhor premature > optimization. Avoiding writing unneeded bloat constructs that are not meant for purpose under hand and confuse the meaning of code is premature optimization? |
woodbrian77@gmail.com: Nov 20 10:02AM -0800 On Friday, November 20, 2015 at 4:23:42 AM UTC-6, Juha Nieminen wrote: > having a function with more than, say 20 or 30 lines of code, > sit back and rethink what you are doing, and whether you could do > it better. I generally agree with this but have a few event loop functions that are a little over 100 lines. They used to be longer and I'm glad to have gotten them to where they are now. One of them is the cmwAmbassador constructor here - http://webEbenezer.net/misc/cmwAmbassador.cc . Brian Ebenezer Enterprises - In G-d we trust. http://webEbenezer.net |
"Öö Tiib" <ootiib@hot.ee>: Nov 20 10:20AM -0800 On Friday, 20 November 2015 10:08:08 UTC+2, David Brown wrote: > thrown and caught in the same function (and it can be sure that the > exception cannot escape), then it is perfectly free to optimise such > code into a "goto". You are correct that compiler may do that. However when I edit the code and replace that try/throw/catch bloat with a goto and a label then the code becomes simpler, easier to read and to understand. So why did I write that bloat at the first place? > I am not saying that such a use of exceptions is a good idea in general, > merely that it is not necessarily as inefficient as you think. I have seen such code in practice at 2010, Visual Studio 2008 did not optimize it and it was 10 times slower and issue was reported about bad performance since it happened in some innermost loop. Even if some more modern compiler can fix it ... I still see no reason to write it. |
Gareth Owen <gwowen@gmail.com>: Nov 20 07:07PM >> than a nested loop with a much cleaner (entirely hypothetical) exit >> mechanism, with the exit condition stored in the loop construct. > I would usually say it was. Fair enough. I will happily accept that it sometimes is, but boldly assert that it sometimes isn't. Incidentally, TC++PLv3 has some interesting comments on using exceptions for purposes other than error handling, which I'll precis as "you can do it, and sometimes it will simplify/clarify an ugly construct ... but you probably shouldn't without good reason." <understatement style="massive"> I suspect Bjarne's example (throwing the return-value from a deeply recursive function) would not be terribly well received here. </understatement> |
"Öö Tiib" <ootiib@hot.ee>: Nov 20 11:19AM -0800 On Friday, 20 November 2015 09:04:25 UTC+2, gwowen wrote: > They're just another language feature, and one that expresses the > desired behaviour "jump out of the normal flow of control and resume at > the end of the loop". It's a goto for people with a fear of 'goto'. 'throw' expresses that anomalous or exceptional condition occurred so the normal processing can not continue anymore and it is interrupted and issue is fowarded for special processing somewhere at higher levels. 'try' expresses that something that may fail under anomalous or exceptional conditions is tried in following block. 'catch' expresses that special processing is in following block. 'throw' inside 'catch' block expresses that only part of special processing was done (some tidying, cleaning or reverting) and the issue is forwarded to even higher levels. Empty 'catch' block indicates that author wants to silence and hide some defects of his. > Let the compiler sort out the exit strategy when it optimises the function! > Would you consider it an abuse of exceptions if the (found) condition > was something that almost never happened? If you manage to show with convincing tests that it is measurably faster than 'goto' then I would consider it (potentially unneeded) optimization. Sometimes every percent of speed is needed so it can be accepted even if ugly misuse. But I can bet you don't manage to come up with such tests. |
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Nov 20 07:57PM On 20/11/2015 19:07, Gareth Owen wrote: > I suspect Bjarne's example (throwing the return-value from a deeply > recursive function) would not be terribly well received here. > </understatement> I throw an exception to cancel a thread sausages. /Flibble |
Gareth Owen <gwowen@gmail.com>: Nov 20 10:32PM > 'throw' expresses that anomalous or exceptional condition occurred so > the normal processing can not continue anymore and it is interrupted > and issue is fowarded for special processing somewhere at higher levels. Unless it doesn't. TC++PLv3 explicitly addresses the fact that while this is a rule of thumb -- and certainly the most common usage -- its not a hard and fast rule and you're free - if not necessarily advised - to use it as just-another-form-of-flow-control. So, so sorry, but if you're just going to make assertions about "what <x> is for", I'm going to take the inventor of the language's word over yours. |
legalize+jeeves@mail.xmission.com (Richard): Nov 20 07:09PM [Please do not mail me a copy of your followup] =?UTF-8?Q?Tobias=20M=C3=BCller?= <troplin@bluewin.ch> spake the secret code >> terms of executable/binary code size. >I find this hard to believe. I still use inline functions in the header, >just not in the class body. Those should be equivalent. To clarify what I think you're saying to make sure I understand it, let me propose a concrete example and you tell me if I got it right. You prefer: class Foo { public: inline int f(); }; int Foo::f() { // possibly multiple statements return 42; } over class Foo { publicL int f() { // possibly multiple statements return 42; } }; Is that correct? At first, I interpreted your earlier statements as implying that you didn't use any inline functions at all. I usually either write free functions in a header and declare them as inline, or I define the function in a class declaration to make it an inline member function. So I had to look up the syntax details on the first example to make sure I got it correctly. Inline specifier <http://en.cppreference.com/w/cpp/language/inline> implies that I decorate the declaration of a function as inline and don't need the inline keyword on the definition. Coliru says this compiles without warning on gcc. -- "The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline> The Computer Graphics Museum <http://computergraphicsmuseum.org> The Terminals Wiki <http://terminals.classiccmp.org> Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com> |
scott@slp53.sl.home (Scott Lurndal): Nov 20 07:33PM > // possibly multiple statements > return 42; > } I'd write it as class Foo { public: int f(void); }; inline int Foo::f(void) { body; } This allows one to move the inline to non-inline without the need to edit the declaration within the class body as well as maintaining readability of the class body. |
Paul <pepstein5@gmail.com>: Nov 20 05:35AM -0800 I was trying to test a very basic example of exception handling but instead I got an ugly crash with a message that the application "requested the Runtime to terminate in an unusual way." I'd be grateful if anyone could explain why the exception is not being handled correctly. The complete code is included below. The what() is what I hoped -- "Vector too long" but (my implementation of) the try/catch/throw basic methodology seems to be awry. Thank you, Paul /* Converting a sorted vector into a binary search tree. Besides being sorted, the vector elements are assumed to be unique */ #include <iostream> #include <vector> #include <cstdlib> #include <stdexcept> #include <set> #include <algorithm> #include <utility> // Generating a random vector of a given length with no duplicates std::vector<int> random(unsigned length) { if(!length) return {}; const int maxLength = 30 * 1000; if(length > maxLength) throw std::runtime_error("Vector too long"); std::set<int> nonDuplicates; int former; std::pair<std::set<int>::iterator, bool>insertion; std::vector<int> result; for(int i = 0; i < length; ++i) do { former = std::rand(); insertion = nonDuplicates.insert(former); } while(!insertion.second); // Assuring no duplicates std::copy(nonDuplicates.begin(), nonDuplicates.end(), std::back_inserter(result)); if(result.size() != length) throw std::runtime_error("Programmer error -- vector is the wrong size"); for(int i = 1; i < result.size(); ++i) if(result[i] <= result[i-1]) throw std::runtime_error("Programmer error -- not sorted"); return result; } struct BST{ BST(int Val):left(nullptr), right(nullptr), val(Val) { } BST* left; BST* right; int val; }; BST* convertToBST(const std::vector<int>& sorted) { if(sorted.empty()) return nullptr; if(sorted.size() == 1) return new BST(sorted[0]); const int midIndex = sorted.size()/2; const int midpoint = sorted[midIndex]; const std::vector<int> left(sorted.begin(), sorted.begin() + midIndex); const std::vector<int> right(sorted.begin() + midIndex + 1, sorted.end()); BST* result = new BST(midpoint); result->left = convertToBST(left); result->right = convertToBST(right); return result; } void printTree(BST* const& tree) { if(tree) { printTree(tree->left); std::cout << tree->val << std::endl; printTree(tree->right); } } int main() { // Test that large vectors are correctly generated std::vector <int> test = random(30 * 1000); for(int i = 0; i < 2; ++i) { std::vector <int> treeVec = random(!i ? 100 : 30 * 1000 + 1); try { printTree(convertToBST(treeVec)); } catch(std::runtime_error& e) { std::cout << e.what(); } } } |
Paavo Helde <myfirstname@osa.pri.ee>: Nov 20 08:53AM -0600 Paul <pepstein5@gmail.com> wrote in > handled correctly. The complete code is included below. The what() > is what I hoped -- "Vector too long" but (my implementation of) the > try/catch/throw basic methodology seems to be awry. You are throwing this exception from the code which is called outside of the try-catch block. Normally one should have all of the main() content in the try-catch block. |
Paul <pepstein5@gmail.com>: Nov 20 10:31AM -0800 On Friday, November 20, 2015 at 2:53:33 PM UTC, Paavo Helde wrote: > You are throwing this exception from the code which is called outside of > the try-catch block. Normally one should have all of the main() content in > the try-catch block. Thanks. I was able to correct this. Paul |
You received this digest because you're subscribed to updates for this group. You can change your settings on the group membership page. To unsubscribe from this group and stop receiving emails from it send an email to comp.lang.c+++unsubscribe@googlegroups.com. |
No comments:
Post a Comment