Next: C++/CLI limitations?
From: Maxim Yegorushkin on 1 Jul 2005 06:57 On Thu, 30 Jun 2005 22:27:44 +0400, David Abrahams <dave(a)boost-consulting.com> wrote: [] >> Using exceptions, what influences the memory? >> And what influences the program size? > > That's also implementation dependent. There is generally no dynamic > memory associated with exception-handling. Not sure if exception throwing is exception-handling, but g++ allocates exceptions on the heap. http://savannah.gnu.org/cgi-bin/viewcvs/gcc/gcc/libstdc%2B%2B-v3/libsupc%2B%2B/eh_alloc.cc?rev=HEAD&content-type=text/vnd.viewcvs-markup -- Maxim Yegorushkin <firstname.lastname(a)gmail.com> [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Thiago R. Adams on 1 Jul 2005 13:02 > Broken preconditions should almost always be handled with an assert > and not an exception. An exception will usually cause a great deal of > code to be executed before you get a chance to diagnose the problem. In much cases asserts work as comentary only; for example: void f(pointer *p){ assert(p != 0); p->f(); } With exceptions the code will be response the error. The TC++PL has an example: template <classX , classA > inline void Assert(A assertion) { if (!assertion ) throw X(); } If think that the most useful is: template <classX , classA > inline void Assert(A assertion) { DebugBreak(); // stops debug if (!assertion ) throw X(); } void f2(int* p) { // ARG_CHECK is an constant: true for checks args Assert<Bad_arg>(ARG_CHECK || p !=0 ); } If code is correct the all callers will be test for arguments. Then I can remove this test. (ARG_CHECK) But is nescessary? When use throw and when use asserts? Two cases: void func(vector &v, int *p) { if (p == 0) throw bad_arg(); // why not? because this functions alread throws v.push_back(p); // push can throw right? } void func(vector &v, int *p) throw() { // maybe is better, becase this function no throw // it has only one contract with callers in debug and release assert(p != 0); // yes I can use reference but is only an example :) *p = v.size() + 10; } I think that is a long and important topic. Performance in exceptions is important to decide the use. My coworks says: "If we doesn't kwown the behavior and performance penalities of exceptions, we will use returns codes, because returns codes is more simple and is known" Thanks! (and sorry my english is not so good) [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: David Abrahams on 1 Jul 2005 21:58 "Maxim Yegorushkin" <firstname.lastname(a)gmail.com> writes: > On Thu, 30 Jun 2005 22:27:44 +0400, David Abrahams > <dave(a)boost-consulting.com> wrote: > > [] > >>> Using exceptions, what influences the memory? >>> And what influences the program size? >> >> That's also implementation dependent. There is generally no dynamic >> memory associated with exception-handling. > > Not sure if exception throwing is exception-handling, but g++ allocates > exceptions on the heap. > > http://savannah.gnu.org/cgi-bin/viewcvs/gcc/gcc/libstdc%2B%2B-v3/libsupc%2B%2B/eh_alloc.cc?rev=HEAD&content-type=text/vnd.viewcvs-markup AFAICT those exceptions are being "dynamically" allocated out of static memory, in static one_buffer emergency_buffer[EMERGENCY_OBJ_COUNT]; That looks like the "magic memory" I was referring to. Am I missing something? -- Dave Abrahams Boost Consulting www.boost-consulting.com [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: David Abrahams on 1 Jul 2005 22:04 "Thiago R. Adams" <thiago.adams(a)gmail.com> writes: >> Broken preconditions should almost always be handled with an assert >> and not an exception. An exception will usually cause a great deal of >> code to be executed before you get a chance to diagnose the problem. > > In much cases asserts work as comentary only; > for example: > > void f(pointer *p){ > assert(p != 0); > p->f(); > } No, they work to stop program execution at the earliest point of detection of the error. > With exceptions the code will be response the error. If preconditions are broken, your program state is broken, by definition. Trying to recover is generally ill-advised. > The TC++PL has an example: That doesn't make it right :) > template <classX , classA > inline void Assert(A assertion) { > if (!assertion ) throw X(); > } > > If think that the most useful is: > template <classX , classA > inline void Assert(A assertion) { > DebugBreak(); // stops debug Stop execution so I can debug the program. Good! > if (!assertion ) throw X(); > } If the assertion fails when there is no debugger, how do you expect the program to recover? > void f2(int* p) { > // ARG_CHECK is an constant: true for checks args > Assert<Bad_arg>(ARG_CHECK || p !=0 ); > } > > If code is correct the all callers will be test for arguments. > Then I can remove this test. (ARG_CHECK) But is nescessary? I don't understand the question. > When use throw and when use asserts? Use asserts to detect that the invariants you have designed into your program are broken. Use throw to indicate that a function will not be able to fulfill its usual postconditions, and when the immediate caller is not very likely to be able to handle the error directly and continue (otherwise, use error return codes and the like). > Two cases: > void func(vector &v, int *p) { > if (p == 0) > throw bad_arg(); // why not? because this functions alread throws Why not? Because, I presume, passing 0 is a precondition violation. It depends on what you put in your documentation. If you say, "you must pass me a non-null pointer," then use an assert. If you say, "if you pass a null pointer I'll throw," well, then throw. However, the former is usually the better course of action. > v.push_back(p); // push can throw right? Yes. So what? > } > > void func(vector &v, int *p) throw() { > // maybe is better, becase this function no throw > // it has only one contract with callers in debug and release > assert(p != 0); Even if it were not nothrow, it would have only one contract. > // yes I can use reference but is only an example :) > *p = v.size() + 10; > } > > I think that is a long and important topic. > Performance in exceptions is important to decide the use. > My coworks says: "If we doesn't kwown the behavior and performance > penalities of exceptions, we will use returns codes, because returns > codes is more simple and is known" Yes, it's a common FUD. It's easy to do some experiments to get a feeling for the real numbers. Do they know the cost in correctness and maintainability of using return codes? -- Dave Abrahams Boost Consulting www.boost-consulting.com [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Alf P. Steinbach on 2 Jul 2005 06:23
* David Abrahams -> Thiago R. Adams: > > > > > If think that the most useful is: > > template <classX , classA > inline void Assert(A assertion) { > > DebugBreak(); // stops debug > > Stop execution so I can debug the program. Good! > > > if (!assertion ) throw X(); > > } > > If the assertion fails when there is no debugger, how do you expect > the program to recover? That's actually a good _C++_ question... ;-) First, the reason why one would like to 'throw' in this case, which is usually not to recover in the sense of continuing normal execution, but to recover enough to do useful logging, reporting and graceful exit on an end-user system with no debugger and other programmer's tools (including, no programmer's level understanding of what goes on). Why that is a problem in C++: the standard exception hierarchy is not designed. Uh, I meant, it's not designed with different degrees of recoverability in mind. At best you can use std::runtime_error for "soft" (in principle recover-and-continue-normally'able) exceptions, and classes derived otherwise from std::exception for "hard" exceptions, but in practice people tend to not restrict themselves to std::runtime_error, and the Boost library is an example of this common practice -- the standard's own exception classes are also examples. So, if you want a really "hard" exception in C++, one that is likely to propagate all the way up to the topmost control level, you'll have to use something else than a standard exception. And even that non-standard exception might be caught (and not rethrown) by a catch(...) somewhere. Which is not as unlikely as it might seem. E.g., as I recall, ScopeGuard does that in its destructorý. Well, then, why not use std::terminate instead? After all, that's what it's for, isn't it? And it's configurable. But no, that's not what it's for. Calling std::terminate does not guarantee RAII cleanup as a "hard" exception would. In short, I know of no good portable solution to this problem in standard C++, and thinking of how extremely easily it could have been supported in the design of the standard exception classes (there was even existing practice from earlier languages indicating how it should be) it's very frustrating. ý) One might argue that calling std::terminate is the only reasonable failure handling in a destructor, even for ScopeGuard-like objects. But the standard already provides that draconian measure for the situation where it's really needed, where you would otherwise have a double exception (which does not exist in C++). Doing it explicitly just removes a measure of control from the client code programmer. -- A: Because it messes up the order in which people normally read text. Q: Why is it such a bad thing? A: Top-posting. Q: What is the most annoying thing on usenet and in e-mail? [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] |