20.5 — Exceptions, classes, and inheritance

Exceptions and member functions

Up to this point in the tutorial, you’ve only seen exceptions used in non-member functions. However, exceptions are equally useful in member functions, and even moreso in overloaded operators. Consider the following overloaded [] operator as part of a simple integer array class:

Although this function will work great as long as index is a valid array index, this function is sorely lacking in some good error checking. We could add an assert statement to ensure the index is valid:

Now if the user passes in an invalid index, the program will cause an assertion error. While this is useful to indicate to the user that something went wrong, sometimes the better course of action is to fail silently and let the caller know something went wrong so they can deal with it as appropriate.

Unfortunately, because overloaded operators have specific requirements as to the number and type of parameter(s) they can take and return, there is no flexibility for passing back error codes or boolean values to the caller. However, since exceptions do not change the signature of a function, they can be put to great use here. Here’s an example:

Now, if the user passes in an invalid index, operator[] will throw an int exception.

When constructors fail

Constructors are another area of classes in which exceptions can be very useful. If a constructor must fail for some reason (e.g. the user passed in invalid input), simply throw an exception to indicate the object failed to create. In such a case, the object’s construction is aborted, and all class members (which have already been created and initialized prior to the body of the constructor executing) are destructed as per usual. However, the class’s destructor is never called (because the object never finished construction).

Because the destructor never executes, you can not rely on said destructor to clean up any resources that have already been allocated. Any such cleanup can happen in the constructor prior to throwing the exception in the first place. However, even better, because the members of the class are destructed as per usual, if you do the resource allocations in the members themselves, then those members can clean up after themselves when they are destructed.

Here’s an example:

This prints:

Member allocated some resources
Member cleaned up

In the above program, when class A throws an exception, all of the members of A are destructed. This gives m_member an opportunity to clean up any resources that were allocated.

This is part of the reason that RAII (reference: 11.9 -- Destructors) is advocated so highly -- even in abnormal circumstances, classes that implement RAII properly should be able to clean up after themselves.

Exception classes

One of the major problems with using basic data types (such as int) as exception types is that they are inherently vague. An even bigger problem is disambiguation of what an exception means when there are multiple statements or function calls within a try block.

In this example, if we were to catch an int exception, what does that really tell us? Was one of the array indexes out of bounds? Did operator+ cause integer overflow? Did operator new fail because it ran out of memory? Unfortunately, in this case, there’s just no easy way to disambiguate. While we can throw const char* exceptions to solve the problem of identifying WHAT went wrong, this still does not provide us the ability to handle exceptions from various sources differently.

One way to solve this problem is to use exception classes. An exception class is just a normal class that is designed specifically to be thrown as an exception. Let’s design a simple exception class to be used with our IntArray class:

Here’s a full program using this class:

Using such a class, we can have the exception return a description of the problem that occurred, which provides context for what went wrong. And since ArrayException is its own unique type, we can specifically catch exceptions thrown by the array class and treat them differently from other exceptions if we wish.

Note that exception handlers should catch class exception objects by reference instead of by value. This prevents the compiler from making a copy of the exception, which can be expensive when the exception is a class object, and prevents object slicing when dealing with derived exception classes (which we’ll talk about in a moment). Catching exceptions by pointer should generally be avoided unless you have a specific reason to do so.

Exceptions and inheritance

Since it’s possible to throw classes as exceptions, and classes can be derived from other classes, we need to consider what happens when we use inherited classes as exceptions. As it turns out, exception handlers will not only match classes of a specific type, they’ll also match classes derived from that specific type as well! Consider the following example:

In the above example we throw an exception of type Derived. However, the output of this program is:

caught Base

What happened?

First, as mentioned above, derived classes will be caught by handlers for the base type. Because Derived is derived from Base, Derived is-a Base (they have an is-a relationship). Second, when C++ is attempting to find a handler for a raised exception, it does so sequentially. Consequently, the first thing C++ does is check whether the exception handler for Base matches the Derived exception. Because Derived is-a Base, the answer is yes, and it executes the catch block for type Base! The catch block for Derived is never even tested in this case.

In order to make this example work as expected, we need to flip the order of the catch blocks:

This way, the Derived handler will get first shot at catching objects of type Derived (before the handler for Base can). Objects of type Base will not match the Derived handler (Derived is-a Base, but Base is not a Derived), and thus will “fall through” to the Base handler.

Rule: Handlers for derived exception classes should be listed before those for base classes.

The ability to use a handler to catch exceptions of derived types using a handler for the base class turns out to be exceedingly useful.


Many of the classes and operators in the standard library throw exception classes on failure. For example, operator new can throw std::bad_alloc if it is unable to allocate enough memory. A failed dynamic_cast will throw std::bad_cast. And so on. As of C++17, there are 25 different exception classes that can be thrown, with more being added in each subsequent language standard.

The good news is that all of these exception classes are derived from a single class called std::exception. std::exception is a small interface class designed to serve as a base class to any exception thrown by the C++ standard library.

Much of the time, when an exception is thrown by the standard library, we won’t care whether it’s a bad allocation, a bad cast, or something else. We just care that something catastrophic went wrong and now our program is exploding. Thanks to std::exception, we can set up an exception handler to catch exceptions of type std::exception, and we’ll end up catching std::exception and all (21+) of the derived exceptions together in one place. Easy!

The above program prints:

Standard exception: string too long

The above example should be pretty straightforward. The one thing worth noting is that std::exception has a virtual member function named what() that returns a C-style string description of the exception. Most derived classes override the what() function to change the message. Note that this string is meant to be used for descriptive text only -- do not use it for comparisons, as it is not guaranteed to be the same across compilers.

Sometimes we’ll want to handle a specific type of exception differently. In this case, we can add a handler for that specific type, and let all the others “fall through” to the base handler. Consider:

In this example, exceptions of type std::length_error will be caught by the first handler and handled there. Exceptions of type std::exception and all of the other derived classes will be caught by the second handler.

Such inheritance hierarchies allow us to use specific handlers to target specific derived exception classes, or to use base class handlers to catch the whole hierarchy of exceptions. This allows us a fine degree of control over what kind of exceptions we want to handle while ensuring we don’t have to do too much work to catch “everything else” in a hierarchy.

Using the standard exceptions directly

Nothing throws a std::exception directly, and neither should you. However, you should feel free to throw the other standard exception classes in the standard library if they adequately represent your needs. You can find a list of all the standard exceptions on cppreference.

std::runtime_error (included as part of the stdexcept header) is a popular choice, because it has a generic name, and its constructor takes a customizable message:

This prints:

Standard exception: Bad things happened

Deriving your own classes from std::exception

You can, of course, derive your own classes from std::exception, and override the virtual what() const member function. Here’s the same program as above, with ArrayException derived from std::exception:

In C++11, virtual function what() was updated to have specifier noexcept (which means the function promises not to throw exceptions itself). Therefore, in C++11 and beyond, our override should also have specifier noexcept.

It’s up to you whether you want create your own standalone exception classes, use the standard exception classes, or derive your own exception classes from std::exception. All are valid approaches depending on your aims.

20.6 -- Rethrowing exceptions
20.4 -- Uncaught exceptions and catch-all handlers

93 comments to 20.5 — Exceptions, classes, and inheritance

  • AbraxasKnister

    I feel like having the error type for a certain type 'A' be a subtype (A::Err) of that type is a good idea to indicate to the programmer that the types have a strong relation. It would also automatically create an exception class for a derived type when inheriting from the type. I thought of the following, but I'm unsure if I did everything correctly and if it's really a good idea:

    I think one of the drawbacks of this is, that if anyone wants to extend A by inheritance

    he can't just overwrite B::Err to something more 'B' specific.

    We could circumnavigate this by something like this

    which sets a default behavior of A::Err and allows deriving classes to change it:

    but I don't know if this is useful enough.

    A second drawback is that B::Err is not a different type from A::Err. Can we somehow achieve that when inheriting B from A a distinct type B::Err is created (automatically)?

    • nascardriver

      Avoid nested types. Although as you said they express a strong relation, you can't forward declare them. This means that you have to include the header with the full class in order to use the nested type. As a result, you get slower compilation times and risk circular dependencies.

      In order for this code to work, we need to include `A`'s header. If `Err` was not a nested type, we could either include `Err`'s header (If it has its own header), or add a forward declaration.

  • hellmet

    In the previous lesson (14.2), it was mentioned "Note that the compiler will not perform implicit conversions or promotions when matching exceptions with catch blocks!", but here, it happily upcasts implicitly. I am assuming this is because of the distinction between user defined types and basic types. Also, implicit casts from/to basic <-> user-types are not done (via constructors etc...), so that's nice! I think mentioning that would be great!

    Also, what if in the constructor, I'm allocating a block of memory and along the way, an exception is thrown? What to do then? I'm assuming delete [] is called on the pointer appropriately? Is this allocated block safely deleted? (Clearly, other RAII members are deleted with their destructors, so no issues there)

    • nascardriver

      Lesson 14.2 now says that implicit casts to a parent class will be performed.
      No manually allocated memory is ever freed for you. If you allocate manually, you have to make sure that the memory gets freed in case of an error.

  • Ulrich


    I tried your example with s.resize(-1) in VS 2019 and the exception triggered was std::length_error, not std::bad_alloc. This behavior is in line with what is written here:

    I believe the reason for this is that an implicit type conversion of -1 to size_t, an unsigned integral type, takes place.

    I seize the opportunity to thank you for the excellent tutorial!

  • Nirbhay


    In the code below:

    on line 41: 'A a(0);' -- class A object 'a' is created and initialised with a value 0.. this means in class A, the constructor  'A(int x) : m_x(x)' is executed.
    So why are "Member allocated some resources" and "Member cleaned up" printed?

    How/when are class Member's constructor and destructor called?

    Thank you!

    • All members of class-type get default-constructed.
      `m_member` is a `Member`, which is a class-type, so `Member::Member()` gets called (And the destructor on destruction).
      If `A` had another member of non-class-type, eg. `double`, it wouldn't get initialized.

      • Nirbhay

        So the following sequence happens..

        - On line 41, the program execution directly goes to line 24 and through A's constructor, m_x is initialized to 0.
        - then on line 21 Member m_member gets created(don't know with which value it is initialied) and the Member constructor is called which prints "Member allocated some resources".
        - then from line 25 the body of A's constructor gets executed which raises an exception thereby  destroying all the members of class A, which includes m_member(to destroy this ~Member() gets called and prints "Member cleaned up")
        - then the program execution takes care of the exception by going to catch(int) block in main() and printing "Oops".

        Please correct me if I am wrong and tell me the correct sequence.

        Thank you :)

        • > don't know with which value it is initialied
          None, it just calls `Member::Member()`. That constructor then decides what the members get initialized to (There are no members so nothing gets a value).

          Your sequence is correct :)

  • DecSco

    Just for clarification: the difference between #including <stdexcept> and <exception> is that the base class lives in <exception> and the derived classes live in <stdexcept>?
    Because at least std::runtime_error works when only just including <exception>. Bit confusing.

    EDIT: states that std::runtime_error lives in stdexcept. However, the following compiles and runs just fine with g++:

    • You already found the headers on cppreference, so there's not much I can add to it. <exception> defines the base class `exception` and a bunch of exception-related functions.
      <stdexcept> defines child classes of `exception`.

      > the following compiles and runs just fine with g++
      Your <exception> or <iostream> includes <stdexcept>. This isn't guaranteed. If you use something, include its header.

  • DecSco

    So how do you handle an exception thrown by a constructor? Say, your member is a C-style array, and the "new" command fails.
    Do you then handle it inside the constructor before throwing the exception?

    • Alex

      If you can handle the exception inside the constructor, than you should do so. If you can't, then you can let the exception propagate and let the code creating the object handle the exception.

  • regarding section "When constructors fail" does this also include the same behavior for all the base/parents that might have been already created prior to throwing this exception in the constructor of the current class (i mean in inheritance context) ?

    • Alex

      Yes, if a class constructor throws an exception, all parent classes that have already been created will be destructed in reverse order of creation.

  • Asgar

    Hi. I ran the exact example of "When constructors fail" by coping and pasting onto Eclipse. On my machine the output order was different! It was:

    Member allocated some resources
    Member cleaned up

    When I changed all occurrences of cerr with cout, the output order became:
    Member allocated some resources
    Member cleaned up

    Is there some sort of precedence given to cout over cerr when they both write to the console?

    • Alex

      Since cout and cerr are different streams, there's no guaranteed ordering if you intermix them. I don't think either has precedence, it just depends on when they get flushed to the output device.

      The order of output is only deterministic within a particular stream.

  • Asgar

    Hi. In this example, I see m_member is never initialized even though the destructor is called. How is it then initialized? Would m_x also be initialized to some default if it was taken out of the member initializer list?

  • Asgar

    Hi Alex,

    Thanks for adding more text in the "When constructors fail" section. One tiny question. I notice you've used std::cerr, instead of std::cout. And, inside a catch clause, you've used std::cout, instead of std::cerr. Is it only a matter of choice? I know they both are instances of ostream.



  • Spixmaster

    Is there a reason that the exception classes in the C++ standard library start with a lowercase letter since that is not common for classes?

  • Typo:

    "Many of the classes and operators in the standard library throw exceptions classes on failure."

    Maybe you meant exception classes?

  • Snorkel Ops

    I'm a bit confused.
    When a object gets out of scope, you can not longer access it.

    But how is it possible when we trow an exception that we can use and access it in the catch handler like:

    Appreciate your work Alex and nascardriver!

    • Hi there!

      I'll use a smaller code example for simplicity

      Now, you'd expect @iException to be a reference to @i, but it isn't.
      Quoting the standard (N4762, § 13.1, 3)
      "Throwing an exception copy-initializes (9.3, 10.3.5) a temporary object, called the exception object."
      Line 9 will create a copy of @i, which is being referenced to by @iException.
      @i goes out of scope and dies as you'd expect from other functions, but the exception object is not destructed before the exception handler exits or an @std::exception_ptr referring to the exception object is destroyed.

      The following code outputs "2", indicating the creation of an exception object.

  • Rex

    Can you give me an example when the exception handler have to handle the cleanup for an object, because the constructor threw an exception?
    It's seems a little bit unclear for me and I think its a significant topic.

    • Alex

      I'm not sure I can think of a good case, and upon reflection I think it's more appropriate for the constructor to do the cleanup before throwing the exception -- that way the cleanup is self-contained within the class, and the handler doesn't need to handle that too.

  • Fredolin

    Just as a reminder for myself, what is the effect of const int index and why is it necessary?
    If the parameter would be a reference, it would be clear, because we don't modify the object.
    But it's copy by value, so what is the effect of it?

  • Topherno

    In the ArrayException example at the end where we inherit from std::exception, I think a "noexcept" should be added to the what() override:

    I think it's a C++11 thing, at least according to cppreference. Otherwise I get this compiler error:

    error: exception specification of overriding function is more lax than base version
            const char* what() const { return m_error.c_str();}

    Will you ever do (sub-)section on noexcept? It seems really useful! :)

    • Alex

      Thanks for pointing this out. I've updated the example to note this. I'd like to do an section on this someday. It's super straightforward what noexcept does, so you should be able to learn about it anywhere. Maybe start with

  • jft

    If you override what(), then what() needs to be const (as that is how it is defined in the base class) otherwise it is new function and not overridden. Consider

    This ensures that you actually are overriding a class function and not creating a new one.

    In this case, there is no need to override what(). Consider

    and the throw could become

    which would also display the index value causing the exception.

  • kdart

    In the last code example there is some syntax I haven't seen in any of your lessons yet.  In the operator[] overload function of the IntArray class, you're calling the non-static member function getLength() without referencing an object.  Is this okay?  Will the compiler implicitly convert that statement to this.getLength()?  And would writing this.getLength() be more correct?

    • nascardriver

      Hi kdart!

      this.member is Java/JavaScript and some other languages
      this->member is C++

      > Will the compiler implicitly convert that statement to this.getLength()?
      Yes. When accessing members inside a class you're accessing the current object's members.

      is equivalent to

      > And would writing this.getLength() be more correct?
      The use of this-> helps understanding code, I suggest using it.

    • Alex

      Nascardriver's answer is good. The only thing I differ with is the suggestion to explicitly reference this. Most developers don't reference this explicitly (unless returning *this by reference), as it clutters up the code and makes it harder to read.

  • Logan

    I did the last step turning off the pre-complied header. Thanks, did the trick. Now I can get on with C++ and I will look forward to the tutorial.

    Regards Logan.

    • Alex

      When Visual Studio has precompiled headers turned on (which it does by default), it expects the first line of any code (.cpp) file to be #include "stdafx.h".

      If this is missing, you will get an error.

      One option is to turn off precompiled headers. Another is to ensure the first line is #include "stdafx.h".

      Visual Studio should have created stdafx.h as part of your project when you created the project.

      • Logan

        I see, well the above code has it in the Header file, but not the corresponding  .cpp file. It was done manually, I will experiment more with the add Class option. I take it the precompiled header is not an important thing to use, if I can just turn it off. Is it of any importance in the industry?
        I certainly want to be sure I understand the proper ways to do things. If it's okay to turn certain settings of, then great! Just so long as those settings are not an integral part of programming in a concise way.

        Least it works now. Nothing worse than wasting a load of time on code when you pretty much understand how it all works and then when you go to run it, the thing comes up with errors you can't comprehend. I had problems in the past with copying and pasting, that seems to be a hit and miss affair.

        Thanks all, you are all a great guiding beacon of hope. What the heck would I do without you guys!

        • nascardriver

          I can't reply to your newest comment, I guess there have been to many replies.

          Precompiled headers are meant to speed up compilation, you can turn them off without problems.
          I don't like stdafx.h, because it's Windows stuff. If you decide to use another compiler (Or share code with someone with another compiler) the #include has to be removed before your code can be compiled.

        • Alex

          Yes, they often use precompiled headers in the industry, as it speeds up compilation times. However, it's just a compilation optimization, so if you want to turn it off, there won't be any other ill effects.

  • Logan

    Hi there please can someone help me, I have a problem I cannot get this code to work. I am using Microsodt Visual Studio 2015.

    It is supposed to show a basic setup of a Class, with the Member variables places on the actual Header file. For whatever reason it keeps showing an error. Can you spot what is missing? I also left out the pragma code. Is it better to use it than the #ifndef option? Also wondering how I transfer the colour tags? It transfers when I copy and paste to a word file, but not here.

    Below is the BMI.h  :

    #include "stdafx.h"
    #include <iostream>
    #include <string>

    using namespace std;

    #ifndef BMI_H
    #define BMI_H

    class BMI {
        // default constructor just to set member variables to null states
        //overload constructor is a different way of calling a function, by adding parementers to it.
        //below the overload doesnt need to be passed by reference because we are only entering the value and sending it, we are not chaging it again, so it being a copy doesnt matter.
        BMI(string, int, double);
        //destructor, once the objects function is left it is destroyed out of memory
        //Below are the accesor functions which return member variables
        //typicaly we use get in front as a universal way to identify it
        string getName() const;
        int getHeight() const;
        double getWeight() const;

        //Member variables
        string newName;
        int newHeight;
        double newWeight;



    Below is the BMI.cpp :

    #include "BMI.h"

    //Below is default contructor coresponding code.
        newHeight = 0;
        newWeight = 0.0;

    //below is overload coresponding code.

    BMI::BMI(string name, int height, double weight)
        newName = name;
        newHeight = height;
        newWeight = weight;

        //leave empty
    //below coresponding declaration for accesors
    string BMI::getName() const
        return newName;
    int BMI::getHeight() const
        return newHeight;

    double BMI::getWeight() const
        return newWeight;

    Below is the main.cpp  :

    #include "stdafx.h"
    #include <iostream>
    #include <string>
    #include "BMI.h"

    using namespace std;

    int main()
        string name;
        int height;
        double weight;
            cout << "Enter your name: ";
        cin >> name;
        cout << "Enter your height in inches: ";
        cin >> height;
        cout << "Enter your weight in pounds: ";
        cin >> weight;

        //BMI Student_1;   //we create the object here that automaticly uses the default constructor
        //below if you want to also use overload constructor as well then add the following
        BMI Student_1(name, height, weight);

        cout << endl << "Patients name: " << Student_1.getName() << endl <<
            "Height: " << Student_1.getHeight() << endl <<
            "weight: " << Student_1.getWeight() << endl;

        return 0;

    • nascardriver

      Hi Logan!

      > it keeps showing an error
      Your code compiles and runs fine for me (Using gcc 7.2.0), what's the error you're getting?

      > I also left out the pragma code. Is it better to use it than the #ifndef option?
      #ifndef is better, because #pragma once is not supported by all compilers (I don't know a single one that doesn't though) but #ifndef is more tedious.

      > Also wondering how I transfer the colour tags?
      The code highlighting is done by Visual Studio, it's not part of the source code. learncpp has it's own source code highlighter, just place CODE tags around your code (Yellow box below reply textfield)

    • Logan

      This is the error message I am getting:

      Severity    Code    Description    Project    File    Line    Suppression State
      Error    C1010    unexpected end of file while looking for precompiled header. Did you forget to add '#include "stdafx.h"' to your source?    BMI.main    c:\users\logan\documents\visual studio 2015\projects\bmi.main\bmi.main\bmi.cpp    37

      • nascardriver

        That appears to be a problem with visual studio.

        Glenn Teitelbaum @ Stackoverflow wrote
        Project Properties -> C++ -> Precompiled Headers
        set Precompiled Header to "Not Using Precompiled Header".

        • Logana

          I am at a loss. My entire venture into learning C++ is halted on this until I can get this to work.
          I don't see the options on my version to not have a precompiled Header, other than to create single files. But I don't see how that matters. This is basic stuff, every program is built using Classes, someone must know what exactly I need to do in order to make this program work.

          When you build these multiple files, do you build each one. On the tutorial I just saw him building the main one and it already worked with the Header and .cpp files. Maybe I am not doing something basic.

          If the code works for you, then perhaps my execution of the code is all wrong. Any basic steps I should be following? Should I put them into new files?

          • nascardriver

            Your IDE (Visual Studio) will do everything for you when you press build, there's no need to set up a compilation order and what not.
            The code works for me, because I am using a different compiler than you.
            Google "C1010" and see if you can find a solution to your problem, I don't have Visual Studio, I can't help any further.

            If you can't find a solution but want to continue the tutorials you can do so by using an online compiler (eg. ). Most online compilers don't support multiple files so you'll have to skip some tutorials.
            If you're lucky perhaps someone with Visual Studio will see your comment and help you.

            • Logan

              Thanks, I will checkout another IDE, and least it works the code. So must be something basic at fault. I will setup the files and remove any added settings, or change them around.

  • Curiosity

    Typo Spotted ! There is no need of (IntArray::) at Line No. 11 if you're defining the member function inside the class itself ! It gives an error !
    Thanks For The Great Tutorials tho :)

  • ali

    dear alex,
    why the handler doesn't catch this exception?

    • Alex

      It's complaining about you trying to assign a char pointer to a string literal. This is dangerous, because string literals may end up in read-only memory. If you try and change them, your code will crash.

      You should use this syntax instead:

      That will ensure merhaba is allocated memory that you can safely change.

      • ali

        Oh no, my question wasn't that.
        the question is why handler didn't catch it?
        the program is just running in screenshot (it's in the debug mode)

        here a new screen:

  • Hello Alex, others.

    It turns out that


    have the same effect.

    Is there any difference that I'm not aware of?

  • Lucas

    Hello, great post!
    I am looking for the answer to this question. How does it work when a re-throw an exception. I mean, I have in function C: throw new Derived(), then in function B has the: try{ C() } catch (Base* e){throw e} and then in function A: try{ B() } catch(Derived* e){ //do sth } catch (Base* e) { //do sth2 }. Is it posible to make it work so as in funcion A I can catch the Derived* as it really is? Does it not work polymorfism with exceptions try-catch? Why?
    Thanks in advance for your replies!

  • Matt

    Catch this... Under "Exception classes", in the first sentence, "problem" should be plural:)

  • Ola Sh

    Hello Alex,

    Thanks again for the good tutorial. I followed your example code below; both the catch handlers in main and Derived were executed by the program. Why does the catch handler in main execute if the catch handler in Derived has already handled the exception? Thanks for your help.

    This prints:

    exception caught in Derived
    exception caught in main

    • Alex

      Function try blocks can not absorb an exception and pretend nothing went wrong. They must either throw an exception of their own, or rethrow the same exception.

      So in the case above, the Derived() catch block is rethrowing the exception so that main() can properly handle the object that failed to construct.

  • Alexander Bieniek

    Do exception handlers treat enumerated types as integers? If not, would they be a similar way to find another type of object to throw?

    Also, are similar data types treated the same way? Would a catch block catch a float if the block was looking for a double?

    • Alex

      You can throw and catch enums:

      A catch block for a double won't catch a float, nor would a catch block for an integer catch a char or a short.

  • Inc

    Consider giving a short explanation about function-try-blocks

  • Naga Pushkal

    Hi Alex,

    If an exception is occurred in a constructor, How could we handle them? Can you please elaborate your statement in "When constructors fail" section in this chapter with small example if possible?

    Today I was asked below question in an interview:

    There is a "class A". And "class B" is derived from "class A". An exception is occurred in class A's constructor. So how would "class B" knows about this exception?

    BTW, Merry Christmas :)

    • Alex

      Great questions!

      For normal cases, you'd just ensure creation of the object happened in a try block, catch the exception and handle it:

      The second question is a little more challenging. I think for this, the only solution would be to use a function level try block. See for details.

      Here's a sample I wrote:

      This prints:

      exception caught in Derived
      exception caught in main
  • tata

    Since the object below is anonymous,

    why shouldn't the code below fail, due to the anonymous object being out of its expression scope

    Should the following code be used instead?

    • Alex

      The rule for exceptions is "throw by value, catch by (const) reference". The compiler deals with the lifetime of the exception appropriately (generally by making a copy of the exception so that the reference points to the persisted copy instead of the anonymous object).

      • tata

        Hi, could I check by understanding by repeating/rephrasing the explanation as:

        ArrayException("Invalide index") is indeed a temporary/anonymous object, which counts as a R-value that cannot be referenced by non-const references; moreover, we have the additional problem that this object will be out of scope before reaching the catch block

        The try/catch mechanism circumvents these problems by making a copy of the anonymous/temporary object and passing instead this copy to the catch block

        Most importantly, since the copy is a L-value, one can reference it using non-const references; moreover, the copy is in scope for the catch block

Leave a Comment

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