20.x — Chapter 20 comprehensive quiz

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

Show Solution

M.1 -- Intro to smart pointers and move semantics
20.9 -- Exception specifications and noexcept

47 comments to 20.x — Chapter 20 comprehensive quiz

  • salah

    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  ?

    • nascardriver

      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.

  • Gabe


  • Ged

    There is another library <exception>, but we don't use it because it is already inside <stdexcept> ?

  • Anthony

    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.

  • Louis Cloete

    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:

    • Alex

      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.

  • matrix

    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)

      • matrix

  • missingsemicolon

    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.

  • a

    My solution

  • ChilaKiller

    whats the difference between


  • 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).

  • Sam

    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"

  • Ben

    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!


  • Shawn

    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:


    • 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

  • Help

    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!

    • Alex

      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.

  • Daniel

    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".

  • Daniel

    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."

  • Unknown

    When you add topics to rvalue references and semantics

  • aca4life

    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.

    • Alex

      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.

  • Manik

    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...

  • aakash gupta

    Hello alex,
    can you give me the code by which the '[code']'[/code'] converts a program to your html-style c++ code.

Leave a Comment

Put all code inside code tags: [code]your code here[/code]