|
|
|
#1 |
|
Messages: n/a
Hébergeur: |
Hi Everyone,
I have the following exception class, class E1 { }; class E2 { public: E2(const E1&) { printf("automatic type conversion\n"); } }; int main() { try { throw E1(); } catch(E2 obj) { printf("first handler\n"); } catch(E1 obj1) { printf("second handler\n"); } } IN the above case, the E1 object is not converted into E2 and is handled by the second handler, this suggests that automatic type conversion doesn't happen with exceptions, i was wondering if this is specified in standards and is there any reason for that? Thanks in advance!!! |
|
|
|
#2 |
|
Messages: n/a
Hébergeur: |
Rahul wrote:
> Hi Everyone, > > I have the following exception class, > > class E1 > { > }; > > class E2 > { > public: E2(const E1&) > { > printf("automatic type conversion\n"); > } > }; > > int main() > { > try > { > throw E1(); > } > catch(E2 obj) Don't catch exceptions by value, use a const reference. -- Ian Collins. |
|
|
|
#3 |
|
Messages: n/a
Hébergeur: |
Rahul wrote:
> Hi Everyone, > > I have the following exception class, > > class E1 > { > }; > > class E2 > { > public: E2(const E1&) > { > printf("automatic type conversion\n"); > } > }; > > int main() > { > try > { > throw E1(); > } > catch(E2 obj) > { > printf("first handler\n"); > } > catch(E1 obj1) > { > printf("second handler\n"); > } > } > > IN the above case, the E1 object is not converted into E2 and is > handled by the second handler, this suggests that automatic type > conversion doesn't happen with exceptions, i was wondering if this is > specified in standards and is there any reason for that? It is specified in [15.3/3]. As for a reason, I can only guess. However, I would conjecture that the problem is that when you throw, you do not necessarily have control over the catch. I.e., a library component might throw precisely because it cannot handle the condition locally and wants the client code to supply a catch handler. If you allowed for user-defined conversions in this setting, there could be surprise catch-matches. Best Kai-Uwe Bux |
|
|
|
#4 |
|
Messages: n/a
Hébergeur: |
In article
<9adce868-eb6d-468e-a371-10338ce97a72@i29g2000prf.googlegroups.com>, Rahul <sam_cit@yahoo.co.in> wrote: > Hi Everyone, > > I have the following exception class, > > class E1 > { > }; > > class E2 > { > public: E2(const E1&) > { > printf("automatic type conversion\n"); > } > }; > > int main() > { > try > { > throw E1(); > } > catch(E2 obj) > { > printf("first handler\n"); > } > catch(E1 obj1) > { > printf("second handler\n"); > } > } > > IN the above case, the E1 object is not converted into E2 and is > handled by the second handler, this suggests that automatic type > conversion doesn't happen with exceptions, i was wondering if this is > specified in standards and is there any reason for that? That is correct, according to 15.3. In my opinion, this is a desired behavior, as exception handlers are meant to handle specific exceptions, not simply any exception that can be conveniently converted. Imagine the confusion when you have a more-appropriate exception handler higher up the call tree, and some other exception handler down below preempts it due to automatic type conversion. Note that exception handlers will handle an exception if it is a derived class of its parameter type. -dr |
|
|
|
#5 |
|
Messages: n/a
Hébergeur: |
On Dec 8, 4:04 pm, Ian Collins <ian-n...@hotmail.com> wrote:
> Rahul wrote: > > Hi Everyone, > > > I have the following exception class, > > > class E1 > > { > > }; > > > class E2 > > { > > public: E2(const E1&) > > { > > printf("automatic type conversion\n"); > > } > > }; > > > int main() > > { > > try > > { > > throw E1(); > > } > > catch(E2 obj) > > Don't catch exceptions by value, use a const reference. > > -- > Ian Collins. Why do you say that exception's should be caught by value? is it because of object slicing when a derived class exception is caught by a base class exception handler? |
|
|
|
#6 |
|
Messages: n/a
Hébergeur: |
* Rahul:
> On Dec 8, 4:04 pm, Ian Collins <ian-n...@hotmail.com> wrote: >> Rahul wrote: >>> Hi Everyone, >>> I have the following exception class, >>> class E1 >>> { >>> }; >>> class E2 >>> { >>> public: E2(const E1&) >>> { >>> printf("automatic type conversion\n"); >>> } >>> }; >>> int main() >>> { >>> try >>> { >>> throw E1(); >>> } >>> catch(E2 obj) >> Don't catch exceptions by value, use a const reference. >> >> -- >> Ian Collins. > > Why do you say that exception's should be caught by value? > is it because of object slicing when a derived class exception is > caught by a base class exception handler? On reason is to avoid copy construction. Consider the case where the copy constructor might trow (e.g. allocating a string). A copy construction exception at the throw point is bad but at least you do get an exception -- just not necessarily the one you asked for -- but a copy construction exception at catch point is t r o u b l e. Another reason is efficiency, avoiding the possible copying. And a third reason is clarity: by catching by reference to const you're telling the reader of the source code that you're not going to modify this exception object, and you don't need it copied. Since catching by reference to const is the most common idiom, anything else indicates that for some reason you need something else. Cheers, & hth., - Alf -- 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? |
|
|
|
#7 |
|
Messages: n/a
Hébergeur: |
On Dec 9, 10:34 am, "Alf P. Steinbach" <al...@start.no> wrote:
> * Rahul: > > > > > > > On Dec 8, 4:04 pm, Ian Collins <ian-n...@hotmail.com> wrote: > >> Rahul wrote: > >>> Hi Everyone, > >>> I have the following exception class, > >>> class E1 > >>> { > >>> }; > >>> class E2 > >>> { > >>> public: E2(const E1&) > >>> { > >>> printf("automatic type conversion\n"); > >>> } > >>> }; > >>> int main() > >>> { > >>> try > >>> { > >>> throw E1(); > >>> } > >>> catch(E2 obj) > >> Don't catch exceptions by value, use a const reference. > > >> -- > >> Ian Collins. > > > Why do you say that exception's should be caught by value? > > is it because of object slicing when a derived class exception is > > caught by a base class exception handler? > > On reason is to avoid copy construction. > > Consider the case where the copy constructor might trow (e.g. allocating > a string). > > A copy construction exception at the throw point is bad but at least you > do get an exception -- just not necessarily the one you asked for -- > but a copy construction exception at catch point is t r o u b l e. Aren't exceptions thrown always copied (atleast once) after they are thrown and before they are caught? To make it persistent during the stack unwinding? And if copy construction can throw, it is a problem even before catching the exception. I think the most important reason for not catching exceptions by value is efficiency i.e. we avoid atleast one copy creation of the exception object. The other reason could be writing a generic base exception handler where all derived types can be caught without slicing. |
|
|
|
#8 |
|
Messages: n/a
Hébergeur: |
On Dec 9, 11:27 am, Abhishek Padmanabh <abhishek.padman...@gmail.com>
wrote: > On Dec 9, 10:34 am, "Alf P. Steinbach" <al...@start.no> wrote: > > > > > * Rahul: > > > > On Dec 8, 4:04 pm, Ian Collins <ian-n...@hotmail.com> wrote: > > >> Rahul wrote: > > >>> Hi Everyone, > > >>> I have the following exception class, > > >>> class E1 > > >>> { > > >>> }; > > >>> class E2 > > >>> { > > >>> public: E2(const E1&) > > >>> { > > >>> printf("automatic type conversion\n"); > > >>> } > > >>> }; > > >>> int main() > > >>> { > > >>> try > > >>> { > > >>> throw E1(); > > >>> } > > >>> catch(E2 obj) > > >> Don't catch exceptions by value, use a const reference. > > > >> -- > > >> Ian Collins. > > > > Why do you say that exception's should be caught by value? > > > is it because of object slicing when a derived class exception is > > > caught by a base class exception handler? > > > On reason is to avoid copy construction. > > > Consider the case where the copy constructor might trow (e.g. allocating > > a string). > > > A copy construction exception at the throw point is bad but at least you > > do get an exception -- just not necessarily the one you asked for -- > > but a copy construction exception at catch point is t r o u b l e. > > Aren't exceptions thrown always copied (atleast once) after they are > thrown and before they are caught? To make it persistent during the > stack unwinding? And if copy construction can throw, it is a problem > even before catching the exception. I think the most important reason > for not catching exceptions by value is efficiency i.e. we avoid > atleast one copy creation of the exception object. > > The other reason could be writing a generic base exception handler > where all derived types can be caught without slicing. Yes i think so, they are copied atleast once, and this code illustrates the same, class E { public : E() { printf("in default constructor...\n"); } E(const E& ref) { printf("copy constructor is invoked...\n"); } }; int main() { try { printf("in try\n"); throw E(); } catch(E& ref) { printf("in handler\n"); } return(0); } output is in try in default constructor... copy constructor is invoked... in handler Press any key to continue |
|
|
|
#9 |
|
Messages: n/a
Hébergeur: |
On 2007-12-09 00:56, Dave Rahardja wrote:
> In article > <9adce868-eb6d-468e-a371-10338ce97a72@i29g2000prf.googlegroups.com>, > Rahul <sam_cit@yahoo.co.in> wrote: > >> Hi Everyone, >> >> I have the following exception class, >> >> class E1 >> { >> }; >> >> class E2 >> { >> public: E2(const E1&) >> { >> printf("automatic type conversion\n"); >> } >> }; >> >> int main() >> { >> try >> { >> throw E1(); >> } >> catch(E2 obj) >> { >> printf("first handler\n"); >> } >> catch(E1 obj1) >> { >> printf("second handler\n"); >> } >> } >> >> IN the above case, the E1 object is not converted into E2 and is >> handled by the second handler, this suggests that automatic type >> conversion doesn't happen with exceptions, i was wondering if this is >> specified in standards and is there any reason for that? > > That is correct, according to 15.3. In my opinion, this is a desired > behavior, as exception handlers are meant to handle specific exceptions, > not simply any exception that can be conveniently converted. Imagine the > confusion when you have a more-appropriate exception handler higher up > the call tree, and some other exception handler down below preempts it > due to automatic type conversion. That would never happen since the handlers are tried top down for a match and the first match is used. So if an exact match is above one that would require a conversion the exact match would always be used. I believe that what you were thinking of was the reverse, when the handler requiring a conversion was placed above the exact match, in which case the match requiring a conversion would be used. Notice that this can happen if you have a handler taking a base-class above a handler for a derived class, the handler for the derived class would never be used. -- Erik Wikström |
|
|
|
#10 |
|
Messages: n/a
Hébergeur: |
On Dec 9, 7:27 am, Abhishek Padmanabh <abhishek.padman...@gmail.com>
wrote: > On Dec 9, 10:34 am, "Alf P. Steinbach" <al...@start.no> wrote: > > * Rahul: > > > On Dec 8, 4:04 pm, Ian Collins <ian-n...@hotmail.com> wrote: > > >> Rahul wrote: > > >>> Hi Everyone, > > >>> I have the following exception class, > > >>> class E1 > > >>> { > > >>> }; > > >>> class E2 > > >>> { > > >>> public: E2(const E1&) > > >>> { > > >>> printf("automatic type conversion\n"); > > >>> } > > >>> }; > > >>> int main() > > >>> { > > >>> try > > >>> { > > >>> throw E1(); > > >>> } > > >>> catch(E2 obj) Concerning the original question: basically, the only conversions considered are derived to base, and then only if the base is an unambiguous public base. (In the case of pointers, the conversion to void* is also considered---but you shouldn't be throwing pointers---and in all cases, top level cv qualifiers are ignored. And I think a few very, very basic conversions also take place systematically: array to pointer, for example.) > > >> Don't catch exceptions by value, use a const reference. > > > Why do you say that exception's should be caught by value? > > > is it because of object slicing when a derived class exception is > > > caught by a base class exception handler? > > On reason is to avoid copy construction. > > Consider the case where the copy constructor might trow (e.g. allocating > > a string). > > A copy construction exception at the throw point is bad but at least you > > do get an exception -- just not necessarily the one you asked for -- > > but a copy construction exception at catch point is t r o u b l e. > Aren't exceptions thrown always copied (atleast once) after they are > thrown and before they are caught? To make it persistent during the > stack unwinding? And if copy construction can throw, it is a problem > even before catching the exception. The formal semantics of a throw is copy initialization of the exception somewhere where it won't disappear. As always with copy initialization, there must be an accessible copy constructor, and as always, the compiler is allowed to elide the copy constructor. The exception is not considered as being thrown until this copy is finished, however. If the copy triggers an exception, that exception will be thrown, rather than the original exception. The exception is not considered caught until the code in the catch block is entered, after the copy (if the catch is by value). And exception in this copy will cause terminate to be called. > I think the most important reason > for not catching exceptions by value is efficiency i.e. we avoid > atleast one copy creation of the exception object. Given all the rest that happes when you throw an exception, this is not normally an issue. > The other reason could be writing a generic base exception handler > where all derived types can be caught without slicing. That's probably the original motivation behind the rule to catch by reference. As Alf pointed out, however, catch by reference has become the "normal" way of doing things in C++; anytime you do something else, the reader will wonder why. So even if you're throwing a non-polymorphic object, you should still catch by reference. -- James Kanze (GABI Software) email:james.kanze@gmail.com Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung 9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34 |
|
|
|
#11 |
|
Messages: n/a
Hébergeur: |
On Dec 9, 9:20 am, Rahul <sam_...@yahoo.co.in> wrote:
> On Dec 9, 11:27 am, Abhishek Padmanabh > <abhishek.padman...@gmail.com> wrote: [...] > Yes I think so, they are copied atleast once, and this code > illustrates the same, > class E > { > public : E() > { > printf("in default constructor...\n"); > } > E(const E& ref) > { > printf("copy constructor is invoked...\n"); > } > }; > int main() > { > try > { > printf("in try\n"); > throw E(); > } > catch(E& ref) > { > printf("in handler\n"); > } > return(0); > } > output is > in try > in default constructor... > copy constructor is invoked... > in handler > Press any key to continue This depends on the compiler. The compiler is allowed to elide the copy, and all of the compilers I have access to (g++, Sun CC and VC++) do (and don't output the line "copy constructor is invoked..."). (This depends on the version, however---older versions of g++ did call the copy constructor here.) -- James Kanze (GABI Software) email:james.kanze@gmail.com Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung 9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34 |
|
|
|
#12 |
|
Messages: n/a
Hébergeur: |
On Dec 8, 12:42 pm, Kai-Uwe Bux <jkherci...@gmx.net> wrote:
> Rahul wrote: [...] > > IN the above case, the E1 object is not converted into E2 and is > > handled by the second handler, this suggests that automatic type > > conversion doesn't happen with exceptions, i was wondering if this is > > specified in standards and is there any reason for that? > It is specified in [15.3/3]. > As for a reason, I can only guess. However, I would conjecture that the > problem is that when you throw, you do not necessarily have control over > the catch. I.e., a library component might throw precisely because it > cannot handle the condition locally and wants the client code to supply a > catch handler. If you allowed for user-defined conversions in this setting, > there could be surprise catch-matches. Implementation considerations may also have played a role. Remember that the type matching here takes place at runtime (and so must use some form of RTTI). Derived to base is pretty straight foreward to do dynamically, but anything else would require a lot more information in the RTTI structures, and a lot more work to process it. (Off hand, except for Derived to Base, the only other conversion which needs to be considered dynamically is pointer to void*.) Note that some conversions occur at the throw site, systematically, and thus do not require RTTI to support them. Array to pointer, for example: you can declare a catch with a reference to an array: catch ( int const (&array)[ 5 ] ) for example, but there's nothing you can throw that will match it, because the array will be converted to a pointer at the throw site, before matching starts. -- James Kanze (GABI Software) email:james.kanze@gmail.com Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung 9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34 |
|
![]() |
| Outils de la discussion | |
|
|