Chapter review
Exception handling provides a mechanism to decouple handling of errors or other exceptional circumstances from the typical control flow of your code. This allows more freedom to handle errors when and how ever is most useful for a given situation, alleviating many (if not all) of the messiness that return codes cause.
A throw statement is used to raise an exception. Try blocks look for exceptions thrown by the code written or called within them. These exceptions get routed to catch blocks, which catch exceptions of particular types (if they match) and handle them. By default, an exception that is caught is considered handled.
Exceptions are handled immediately. If an exception is raised, control jumps to the nearest enclosing try block, looking for catch handlers that can handle the exception. If no try block is found or no catch blocks matches, the stack will be unwound until a handler is found. If no handler is found before the entire stack is unwound, the program will terminate with an unhandled exception error.
Exceptions of any data type can be thrown, including classes.
Catch blocks can be configured to catch exceptions of a particular data type, or a catch-all handler can be set up by using the ellipses (…). A catch block catching a base class reference will also catch exceptions of a derived class. All of the exceptions thrown by the standard library are derived from the std::exception class (which lives in the exception header), so catching a std::exception by reference will catch all standard library exceptions. The what() member function can be used to determine what kind of std::exception was thrown.
Inside a catch block, a new exception may be thrown. Because this new exception is thrown outside of the try block associated with that catch block, it won’t be caught by the catch block it’s thrown within. Exceptions may be rethrown from a catch block by using the keyword throw by itself. Do not rethrow an exception using the exception variable that was caught, otherwise object slicing may result.
Function try blocks give you a way to catch any exception that occurs within a function or an associated member initialization list. These are typically only used with derived class constructors.
You should never throw an exception from a destructor.
The noexcept exception specifier can be used to denote that a function is no-throw/no-fail.
Finally, exception handling does have a cost. In most cases, code using exceptions will run slightly slower, and the cost of handling an exception is very high. You should only use exceptions to handle exceptional circumstances, not for normal error handling cases (e.g. invalid input).
Chapter quiz
1) Write a Fraction class that has a constructor that takes a numerator and a denominator. If the user passes in a denominator of 0, throw an exception of type std::runtime_error (included in the stdexcept header). In your main program, ask the user to enter two integers. If the Fraction is valid, print the fraction. If the Fraction is invalid, catch a std::exception, and tell the user that they entered an invalid fraction.
Here’s what one run of the program should output:
Enter the numerator: 5 Enter the denominator: 0 Invalid denominator
![]() |
![]() |
![]() |
Hi nascardriver,
As you said in the previous lessons that we can surrounde our function ,escpecially constructor, by try-block.
In my code I splited the initialization from the declaration of the Fraction class to access it (Fraction object) outside the try-block: if 'try' was used in constructor, then I have to define my object inside try-block in main function, thus I can't access it outside that block, so does the code good in this case ?
This only works if you have control over the object you're creating (ie. you're the author of `Fraction`) and the object can be created without being initialized (eg. it doesn't have a reference member variable).
A more versatile solution is to dynamically allocate `f`. That way you can declare it without initializing it, and then really initialize (Not assign) it in the try-block.
If you don't yet know what `unique_ptr` and `make_unique` are, they're explained in the next lesson. This could be done with `new` and `delete` as well.
That's great thank you so much
Quiz:
There is another library <exception>, but we don't use it because it is already inside <stdexcept> ?
The exception header only includes std::exception. The stdexcept includes all of the derived classes, like std::runtime_error.
Some of this confused me to start with.
This line is straightforward. The * operator dereferences a pointer, so let's just return the dereferenced pointer, and everybody's happy.
This is more subtle. My first thought was that we were looking to dereference again, since the -> operator dereferences a pointer, as above. But then I saw that it's closer to meaning that since -> usually operates upon a pointer, we must here return a pointer. But then this would be more like preparing it for the operation than carrying out the operation, which are slightly different things.
Is that right? Because it still doesn't seem to be the correct reasoning to me. Could you unmuddle my thinking somehow?
Thanks :)
@operator-> can return references, but then you won't be able to use the returned value in a convenient way
The member lookup is done automatically for you. So although you're returning a pointer, the caller doesn't have to use @operator-> or indirection on the returned object again.
Hi Alex!
A couple of comments about the code in the quiz:
1) Your expected output and your exception's text doesn't match. You expect "Your fraction has an invalid denominator." but you will get "Invalid denominator" instead.
2) The code getting input is nearly identical except for the prompt. Why not extract it into a function like this:
and then use it like this:
1) Fixed, thanks!
2) You certainly can. However, my take is that it isn't worth the additional complexity (a new function + 3 extra lines of code) just to remove 2 lines of otherwise redundant code.
Regarding 2): True. If, however, you want to actually handle the possible error, it does make sense to extract a function (because error handling with std::istream isn't trivial...).
Agreed!
I'm getting this error while overloading "<<" operator:
Severity Code Description Project File Line Suppression State
Error C2679 binary '<<': no operator found which takes a right-hand operand of type 'Fraction' (or there is no acceptable conversion)
Please post your code.
So I wrote a programm that should find all primenumbers from 2 to a user-defined max.
It works but it is confusing. Any suggestions how I could write it better/clearer? :)
* Line 37, 9, 46, 57: Initialize your variables with brace initializers.
* Line 20, 22, 27, 69: Limit your lines to 80 characters in length for better readability on small displays.
* Program in english.
* Missing printed line feed at the end of your program.
* Line 10, 92: Comparison of different types.
* Line 7: @n should be const.
* You're using the same name style for function and variable. Neither consistently.
* @doesnumberexistsalready: Use @std::find.
* Line 50+: Initialize @index to 2 to avoid the calculation in every loop cycle.
* Storing all numbers is a waste of memory. You can generate them when you need them.
* Line 69, 73, 75: Triple calculation of the same number.
I didn't check your logic, it seems way too complicated for generating prime numbers. Have a look at some other approaches online.
My solution
whats the difference between
and
The latter is better because it's less redundant. Quiz solution updated!
Hi,
solved the quiz thus:
so effectively had the whole of my main function within the try block. This ensures that any errors are caught (I feel).
Your catch won't catch everything. You need
Other than that, you're still using direct initialization.
Typo: "If no try block is found or not catch blocks matches" should be "If no try block is found or no catch block matches"
Typo fixed! Thanks again.
EXCEPTIONal circumstances indeed :)! Thanks for the great tutorial. I've been working as a software analyst for about 8 months now, and I owe this tutorial for allowing me to start my second career!
Thanks!
Hey Alex,
Thank you for the great content! I've tried to use templates for this exercise but I couldn't seem to make it work. I get weird errors on line 1 that I've never had before.
Here is my code:
Thanks!
Hi Shawn!
Disable precompiled headers in your project settings and remove
Suggestions so far:
* Don't use "using namespace"
* Line 11, 12 will only work when @T is an arithmetic type, have a look at <type_traits>
* Initialize your variables with uniform initialization
* Use std::numeric_limits<std::streamsize>::max() rather than 32767
Thanks for the advice!
However I still get these weird problems....
Severity Code Description Project File Line Suppression State
Error LNK2019 unresolved external symbol "class std::basic_ostream<char,struct std::char_traits<char> > & __cdecl operator<<(class std::basic_ostream<char,struct std::char_traits<char> > &,class Fraction<int> const &)" (??6@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@std@@AAV01@ABV?$Fraction@H@@@Z) referenced in function _main ch14 C:\Users\Shawn\source\repos\ch14\ch14\ch14.obj 1
Severity Code Description Project File Line Suppression State
Error LNK1120 1 unresolved externals ch14 C:\Users\Shawn\source\repos\ch14\Debug\ch14.exe 1
Is it due to the fact that I'm not using <type_traits> (even though I'm only using arithmetic types in my program)?
Template functions need to be defined inside the class (unless you want to do specialization, which I don't like).
Thanks, it worked!
(Sorry for the delay in my response, I go caught up in stuff)
hi Alex,
I wounder why u put in private int m_numerator = 0; and int m_denominator = 1; while in constructor we already do this they assign any argument Fraction(int numerator = 0, int denominator = 1). Couldn't i do just say in private int m_numerator; and int m_denominator; or is it any purpose for having both in constructor and assign in private ( cause if we call Fraction f; it still will in constructor put numerator = 0 and denominator = 1) ?
Thanks in advance!
The non-static member initializers will be ignored in favor of the ones in the constructor. I included them just as a defensive programming mechanism. In this program, it will never get used. But if we later extended the class, we'd be sure that our numerator and denominator would be initialized to some reasonable value no matter what instead of remaining uninitialized.
You are correct. I was copy/pasting on my phone and forgot to update the copy.
I meant to suggest changing "not ever" to "never".
Thanks for clarifying. I agree this is clearer. Lesson updated.
Suggest grammar fix:
Change: "You should not ever throw an exception from a destructor."
to: "You should not ever throw an exception from a destructor."
Those look identical to me. Am I missing something obvious? :)
Alex,
When you add topics to rvalue references and semantics
I think rvalue references will be the next lesson I write, so should be soon.
After neither my nor your solution compiled I found out that std::exception doesn't have a string/char* constructor. But since the derived error classes own such a constructor I used std::domain_error from <stdexcept> instead and it worked.
http://www.cplusplus.com/reference/exception/exception/exception/
Interesting, I didn't realize that a std::exception constructor that took a string was non-standard. I'll update the code accordingly.
Doing a little investigation, most developers who want to use a standard exception with a customized error message use std::runtime_error. I've updated lesson 14.5 to include a note about this, as well as to fix a few other related issues.
Can you give tutorials on designing animation programs with c++. I want to make animations with c++. I didn't understand any line of opengl and directx...
Maybe someday I'll get to graphical applications, but it's unlikely to happen anytime soon.
Hello alex,
can you give me the code by which the '[code']'[/code'] converts a program to your html-style c++ code.
Right now, it's being done via a WordPress plugin called Crayon.
How can i set the theme of your site in my wordpress site