0

Today I was very surprised when my try catch block didn't work as I inticipated. I expected it to exit with a desired error message when an error in my try block was found.

This is my very simple code:

#include <iostream>
#include <vector>
#include <stdexcept>

using namespace std;

class Book {
public:
    string title {};
    string author {};
    int pages {};
    int readers {};
    
    Book (string t, string a, int p)
            : title{t}, author{a}, pages{p}, readers{0}
    {
        try{
           if (pages <= 0)
             throw invalid_argument ("Invalid page input");
        }
        catch (const invalid_argument& e){
            cout << e.what() << endl;
            exit; //Shoudn't it exit here?

        }
    }

    void print()
    {
        cout << "Name: " << title << "\nAuthor: " << author 
             << "\nPages: " << pages << "\nReaders: " << readers << endl;
    }
    
};


int main()
{
   Book book_1 ("Harry Potter", "JK Rowling", 0); //should exit here and give error?
   book_1.print();
  
    return 0;
}

I thought the program should exit when I first created an object named book_1. It shoudn't even go into printing it. Why is my program not exiting?

The ouput I'm getting is:

Invalid page input
Name: Harry Potter
Author: JK Rowling
Pages: 0
Readers: 0
Cidrant
  • 7
  • 2
  • 4
    The point of `catch` is to catch the exception, so your program doesn't crash when it is thrown... You can type `throw;` within `catch` block to rethrow caught exception, it will then continue going up the stack and eventually terminate the program (unless caught somewhere else). Or don't use `try`/`catch` in the first place. – Yksisarvinen May 08 '22 at 17:53
  • So I can literally not crash my program with try catch block? The point of using a try catch block is to get a nice error message without the default terminate() things. I want a nice error message but I want it to crash aswell once that error message has been printed. – Cidrant May 08 '22 at 17:57
  • 2
    @Cidrant *"The point of using a try catch block is to get a nice error message without the default terminate() things."* -- no, the point of using a try-catch block is to intercept the exception before it crashes your program. It can be used to get a nice error message, but the nominal purpose is to avoid crashing. To get the crash as well, add the command `throw;` to the `catch` clause (after displaying the output; in this setting, `throw` will be similar to `exit` in that the program will end at that point). – JaMiT May 08 '22 at 17:59
  • You can call `std::exit` or `std::terminate` or `std::abort` within `catch` block, but I'm not sure which if either would not print anything to the console. It can be also setting of the console instead, some print e.g. `Application ended with code X` by default. – Yksisarvinen May 08 '22 at 18:01
  • @JaMiT Yeah I am aware of that. When I try adding throw; in the catch block, I will get this output: Invalid page input terminate called after throwing an instance of 'std::invalid_argument' what(): Invalid page input. Which is not a nice error message. Is there not a good way in c++ to throw an exception with a nice message and crash it? – Cidrant May 08 '22 at 18:03
  • 3
    @Cidrant *Why is my program not crashing?* -- Be careful with the terminology. The term "crash" is not the same as "throw an error, catch it, and exit the program". A crash is an instant stoppage of the program that has no initial explanation of why the program has terminated. It's the same thing with `assert()` -- if an `assert()` is triggered, that is not a "crash". – PaulMcKenzie May 08 '22 at 18:07
  • In godbolt, both [`std::exit`](https://godbolt.org/z/a7dfcvP4e) and [`std::abort`](https://godbolt.org/z/5Y56rMdqP) do not print anything extra, but again, it may be terminal specific. – Yksisarvinen May 08 '22 at 18:07
  • Yeah thats true @JaMiT. I simply want to exit the program with a nice error message when an invalid input has occured. However when I do "exit" after "cout << e.what << endl" It still wont exit the program. It just goes on like nothing happened. – Cidrant May 08 '22 at 18:08
  • @PaulMcKenzie Yes you are right. However I am still struggling with exiting the program even if I type "exit;" in my catch block. I thought it would exit my program after my error message was printed out? – Cidrant May 08 '22 at 18:11
  • @Cidrant -- First, do you see why your initial program behaves the way it does? What if the exception wasn't fatal, and you wanted the program to keep going? How would your initial (not changed) code be able to detect that yes, I want the program to proceed, even though an exception was thrown? Maybe like "this book is invalid, throw an exception so I can record its name, and read the next book's information". Something like that. Ok, now that you've gotten that out of the way, maybe you should add to your post your *changed* code, so that we can see what you are doing right now. – PaulMcKenzie May 08 '22 at 18:16
  • If your goal is to modify the "terminate" message, the language allows you to override the default. Just put at the beginning of `main`: `std::set_terminate([]{ std::cout << "Oh no!" << std::endl; std::abort(); });`. If you want to also print something about the exception, then the `try`/`catch` should be in `main` enclosing its whole body. This way you can catch all exceptions from the program and after the `catch` handler the program will simply exit since there is nothing left in `main` after it. Also, to exit the program you need `std::exit(1);` or `std::abort();`, not `exit;`. – user17732522 May 08 '22 at 18:25
  • And finally, there is [`assert`](https://en.cppreference.com/w/cpp/error/assert) which you would use to check for actual logic errors in the program which should never happen and are programming bugs. Typically failing an `assert` will give you a nice error about the specific assertion that failed. (Assertions are however not meant to check for logically-allowed, but exceptional conditions. They are typically ignored in non-debug builds.) – user17732522 May 08 '22 at 18:35
  • 2
    [Turn on warnings](https://stackoverflow.com/questions/57842756/why-should-i-always-enable-compiler-warnings). The "statement" `exit;` is a no-op, as opposed to, for example, `exit(1);`. Also , you might want to look at [How to end C++ code](https://stackoverflow.com/questions/30250934/how-to-end-c-code). – JaMiT May 08 '22 at 18:43

2 Answers2

1

Try exit(0) or std::terminate() instead of exit; you have to use parentheses to invoke the function. With out brackets exit will just be an unused number representing the address of that function.

Lefteris E
  • 2,806
  • 1
  • 24
  • 23
-1

I thought the program should crash when I first created an object named book_1.

Your assumption/understanding is incorrect. In C++, we can raise an exception by throwing an expression. Moreover, the type of the thrown expression determines the handler that will be used to deal/handle with that exception.

Additionally, the selected handler will be the one that:

a) matches the type of the thrown object,

b) is nearest in the call chain.

This means that the control is passed from the throw(where you "raised" the exception) to the matching catch.


Why is my program not crashing?

Applying this to your example, we see that you're throwing an an object of type std::invalid_argument and you've a handler that matches the type of the thrown object. Hence the control will be passed to that handler and we get the output Invalid page input.

Jason
  • 36,170
  • 5
  • 26
  • 60