Exception handling once an object has been created - c++

I am a bit confused on where I should throw an exception and where I should catch it. Right now I am throwing an invalid_argument as soon as someone creates a book with an invalid page.
In my main function I am then creating a book with an invalid page and I am catching that exception and writing out the message. Is this how you are supposed to do it? Because right now I am only catching one single instance of a book. If I tried to create another book outside the try catch block with an invalid page I woudnt be able to catch it. Is this really necessary? Is this how I'm supposed to handle exceptions?
#include <iostream>
#include <string>
#include <stdexcept>
using namespace std;
class Book
{
public:
string title {};
string author {};
int pages {};
int readers {};
Book(string const& t, string const& a, int const p)
: title{t}, author{a}, pages{p}, readers{0}
{
if (pages <= 0)
throw invalid_argument ("Invalid page!");
}
void print() const
{
cout << "Title: " << title << "\nAuthor: " << author
<< "\nPages: " << pages << "\nReaders: " << readers << endl;
}
};
int main()
{
try
{
Book book_1("Harry Potter", "JK Rowling", 0);
}
catch(const exception& e)
{
cerr << "Exception: " << e.what() << endl;
}
//book_1.print();
return 0;
}

Yes, if you call a function that may throw an exception, at some point, you will need to handle it. The way to do it is to catch the exception.
Is it really necessary?
Well it depends. If in your case you ensure that you won't create your objects with invalid arguments, you don't need to catch an exception that'll never be raised.
Exception handling is only required when you don't know (you have no guarantee), for example when the page parameter is given from a user input, a file or anything that is unknown/not predictable/not controlled by the code base.
That being said, in your case you can do even better, just replace:
int pages;
with:
unsigned int pages;
And then it would not be possible to give an invalid number anymore. Which means you can completely remove the exception handling off your code.
The above proposal didn't take into account that 0 is considered invalid as well.

You should catch and handle the exception where it makes sense for the program.
First of all, your program always throws the exception independent of input, because the 0 is hard-coded. This doesn't seem to be a use case for an exception. This seems to be a logic error and so it should be considered a bug that needs fixing. Why should it make sense to try to create a guaranteed invalid book?
But let's suppose the number of pages is given by user input. Then the next issue would be that you can't print a book that failed to be created. So book_1.print(); must be part of the try block.
Let's suppose you have a second book book_2, also created from input from the user. You need to ask yourself then whether it makes sense for the program logic to continue creating and using the second book if creating the first one failed.
If failing to create the first book means that there is no point in continuing with the second book, then just put everything in one try block, e.g.:
try
{
Book book_1(/*...*/);
book_1.print();
Book book_2(/*...*/);
book_2.print();
}
catch(const exception& e)
{
cerr << "Exception: " << e.what() << endl;
}
When either of the book creations fail, the program will continue executing in the catch handler and then after it, skipping over the rest of the book creations and printing. But if book_1 didn't throw on construction, then it will be printed before book_2 is "checked".
Maybe you would want
try
{
Book book_1(/*...*/);
Book book_2(/*...*/);
book_1.print();
book_2.print();
}
catch(const exception& e)
{
cerr << "Exception: " << e.what() << endl;
}
With this the program will not print any book if creation of either book fails.
If it does make sense for the program to continue execution if creation of the first book failed, then use two try/catch statements to handle the errors individually:
try
{
Book book_1(/*...*/);
book_1.print();
}
catch(const exception& e)
{
cerr << "Exception: " << e.what() << endl;
}
try
{
Book book_2(/*...*/);
book_2.print();
}
catch(const exception& e)
{
cerr << "Exception: " << e.what() << endl;
}
You might want to consider using a function or arrays and loops to make this less redundant, for example if the goal is to just repeatedly take user input, create a book and then print it, a simple loop will be helpful:
while(true)
{
try
{
/* take user input here */
if(/* some exit condition */)
{
break;
}
Book book(/* arguments from user input */);
book.print();
}
catch(const exception& e)
{
cerr << "Exception: " << e.what() << endl;
}
}
This loop will run until the exit condition is satisfied. If any standard exception (from book creation or the input operation) is thrown, the exception message will be printed and the loop continues anew.
(As an additional note: In all of the examples above all exceptions inherited from std::exception thrown in the try blocks will be caught. This means not only the invalid_argument exception from the book creation, but e.g. any exception thrown by .print() or the input handling. You may not want to handle these the same way as the invalid book creation. For example an exception from input operations could mean that there is no way for the program to continue the loop. Therefore it makes sense to use a custom class (maybe inherited from std::invalid_argument) for the throw in Book's constructor and catch only that. This way you can handle the invalid book creation specifically.)

Related

Do you need to know what exception is going to occur to handle them in C++?

<C++>In exception handling, do you need to know what exception and where an exception is going to occur? Can you make a code which will print and notify us that an exception occurred somewhere in the program. I mean I have a program in which I don't know if an exception will occur or not, if one was to occur, then it will print to notify us.
Exception handling is something you should design for, and in fact it works very well together with RAII (https://en.cppreference.com/w/cpp/language/raii).
(Notr On embedded platforms using exceptions, is not so popular because of some runtime overhead). What I personally like about exceptions is that it separates error handling from the normal program flow (there will be hardly any if then else checks when done right)
// Exception handling should be part of your overal design.And many standard library functions can throw exceptions, It is always up to you where you handle them.
#include <iostream>
#include <string>
#include <stdexcept>
int get_int_with_local_exception_handling()
{
do
{
try
{
std::cout << "Input an integer (local exception handling, enter a text for exception): ";
std::string input;
std::cin >> input;
// stoi is a function that can throw exceptions
// look at the documentation https://en.cppreference.com/w/cpp/string/basic_string/stol
// and look for exceptions.
//
int value = std::stoi(input);
// if input was ok, no exception was thrown so we can return the value to the client.
return value;
}
// catch by const reference, it avoids copies of the exception
// and makes sure you cannot change the content
catch (const std::invalid_argument& e)
{
// std::exceptions always have a what function with readable info
std::cout << "handling std::invalid_argument, " << e.what() << "\n";
}
catch (const std::out_of_range& e)
{
std::cout << "handling std::out_of_range, " << e.what() << "\n";
}
} while (true);
}
int get_int_no_exception_handling()
{
std::cout << "Input an integer (without exception handling, enter a text for exception): ";
std::string input;
std::cin >> input;
int value = std::stoi(input);
return value;
}
int main()
{
try
{
// this function shows you can handle exceptions locally
// to keep program running
auto value1 = get_int_with_local_exception_handling();
std::cout << "your for input was : " << value1 << "\n";
// this function shows that exceptions can be thrown without
// catching, but then the end up on the next exception handler
// on the stack, which in this case is the one in main
auto value2 = get_int_no_exception_handling();
std::cout << "your input was : " << value1 << "\n";
return 0;
}
catch (const std::exception& e)
{
std::cout << "Unhandled exception caught, program terminating : " << e.what() << "\n";
return -1;
}
catch (...)
{
std::cout << "Unknown, and unhandled exception caught, program terminating\n";
}
}
Yes and no.
No, because any exception thrown via throw some_exception; can be catched via catch(...).
Yes, because catch(...) is not very useful. You only know that there was an excpetion but not more.
Typically exceptions carry information on the cause that you want to use in the catch. Only as a last resort or when you need to make abolutely sure not to miss any excpetion you should use catch(...):
try {
might_throw_unknown_exceptions();
} catch(std::exception& err) {
std::cout << "there was a runtime error: " << err.what();
} catch(...) {
std::cout << "an unknown excpetion was thrown.";
}
The C++ standard library uses inheritance only sparingly. Exceptions is only place where it is used extensively: All standard exceptions inherit from std::exception and it is good practice to inherit also custom exceptions from it.

Why does std::exception catch my exception before std::bad_alloc?

Problem : I am using both std::exception and std::bad_alloc to catch exception. Something is wrong with the order of the try catch that I am using. I attached sample code for reference.
Expected : If my error is bad_alloc then the bad_alloc exception is thrown.
Observed : My error is bad_alloc, but exception is thrown.
Sample Code :
#include "stdafx.h"
#include <iostream>
#include <exception>
using namespace std;
void goesWrong()
{
bool error1Detected = true;
bool error2Detected = false;
if (error1Detected)
{
throw bad_alloc();
}
if (error2Detected)
{
throw exception();
}
}
int main()
{
try
{
goesWrong();
}
catch (exception &e)
{
cout << "Catching exception: " << e.what() << endl;
}
catch (bad_alloc &e)
{
cout << "Catching bad_alloc: " << e.what() << endl;
}
return 0;
}
You have to put your exceptions in reverse order, regarding their inheritance relationship. std::exception is the parent class of std::bad_alloc, that is why it is found before in the catch list. So you have to transform your code to be:
try {
goesWrong();
}
catch (bad_alloc &e)
{
cout << "Catching bad_alloc: " << e.what() << endl;
}
catch (exception &e)
{
cout << "Catching exception: " << e.what() << endl;
}
You're not limited to catch objects: you can throw integers, chars... whatever. In that case, catch(...) is the only secure way to catch them all.
That said, using objects from the standard class library is the advised way to do it. And in this case, since std::exception is the base class for all (standard) exceptions, it will catch all possible exceptions thrown.
You can create your own exception classes deriving them from std::exception, or from std::runtime_error, for example, my personal choice.
Hope this helps.
In C++, the order in which exception handlers are listed is taken into account when matching handlers to exceptions. The first handler which can handle the exception will be called, even if there is a better match further down the list. This is different from Java or C#, where only the best match will be called (and the compiler forces you to put it at the top of the list).
As the exception is passed by reference, polymorphism applies; this means that a subclass can be passed to a handler that expects its parent class. Since std::bad_alloc is a subclass of std::exception, it will be handled by the first catch block.
To get the behaviour you expected, put the catch blocks the other way round:
catch (bad_alloc &e)
{
cout << "Catching bad_alloc: " << e.what() << endl;
}
catch (exception &e)
{
cout << "Catching exception: " << e.what() << endl;
}
This way round, std::bad_alloc will match the first handler, while std::exception and all its other subclasses will match the second.

c++ exceptions not caught in visual studio 2017

I can't find a way to actually enable c++ exception handling in visual studio 2017. Maybe I am missing something trivial. I've searched a lot and found nothing that solves this simple issue.
Even this simple code does not act as expected:
#include <iostream>
//#include <exception>
int main(int argc, char *argv[])
{
try
{
int j = 0;
int i = 5 / j;
std::cout << "i value = " << i << "\n";
std::cout << "this line was actually reached\n";
}
catch (...)
//catch (std::exception e)
{
std::cout << "Exception caught!\n";
return -1;
}
std::cout << "Exception was NOT caught!\n";
std::cin.get();
}
When I execute this simple code the program crashes, like the exception is never caught, I tried also with std::exception variant, and i get the same result.
The division by zero is just an example, I could have wrote also something like this:
ExampleClass* pClassPointer = null;
pClassPointer->doSomething();
and expected that a nullpointer exception was automatically thrown and captured by the catch(...) clause.
Just as an information, I added the line:
std::cout << "i value = " << i << "\n";"
otherwise the compiler optimization would have skipped most of the code and the result (in RELEASE mode) was:
this line was actually reached
Exception was NOT caught!
In the properties page of the project, in the option "Enable C++ Exceptions" I have the value: "Yes (/EHsc)", so I think exceptions should be actually enabled.
Am I missing something?
Thank you in advance.
Andrea
---- Edit
I actually just found out that changing the option "Enable C++ Exceptions" with the value "Yes with SEH Exceptions (/EHa)" instead of "Yes (/EHsc)" allows to capture access violation and divide by zero errors in the catch(...) clause.
I've also found very useful information about this subject and whether or not is a good idea to catch those type of exceptions in the replies to this other thread:
Catching access violation exceptions?
In C++ you throw an exception, and, having done that, you can catch it. If you didn't throw it, you can't catch it.
Confusingly, there are many kinds of errors that are generically referred to as "exceptions". This is especially true in floating-point math, where anything that goes wrong is a "floating-point exception". It's the same word, but those exceptions are not C++ exceptions, and you cannot reliably catch them.
In general, when something goes wrong in your program you get undefined behavior, that is, the language definition does not tell you what the program does. So you're on your own: if your compiler documents what it does when a program divides an integer value by 0, then you can rely on that behavior. If not, don't count on anything.
#include <iostream>
int main(int argc, char *argv[])
{
try
{
int j = 0;
int i ;
if(j==0)
throw j; // you have throw some variable or atleast use throw for your
//catch to work
std::cout << "i value = " << j/5<< "\n";
std::cout << "this line was actually reached\n";
}
catch (int e) /*catch will work only if the data type of argument matches with the thrown variable's data type if it does not then the compiler's default catch will run*/
{
std::cout << "Exception caught!\n";
return -1;
}
std::cout << "Exception was NOT caught!\n";
std::cin.get();
}
if u still have any questions ask in comments!

How to add information about the topmost call/context to an exception

I would like to add information on what the program was about to do to my
exception handling. The old code had one big try-block around everything:
try {
read_cfg(); // a sub call might throw runtime_error
operation1();
operation2();
}
catch (std::exception& e) {
std::cerr
<< "Error: " << e.what() << ", "
// FIXME: also show what we were trying to do
// FIXME: and what a user could try
<< "\n";
}
Example error message:
Error: file "foo.cfg" not found, while reading configuration.
Please make sure the file exists.
I converted the try-block into three blocks, but this feels odd:
try {
read_cfg(); // a sub call might throw runtime_error
}
catch (std::exception& e) {
std::cerr
<< "Error: " << e.what() << ", "
<< "while reading configuration."
<< "\n";
}
try {
operation1();
}
catch (std::exception& e) {
std::cerr
<< "Error: " << e.what() << ", "
<< "while performing operation 1."
<< "\n";
}
try {
operation2();
}
catch (std::exception& e) {
std::cerr
<< "Error: " << e.what() << ", "
<< "while performing operation 2."
<< "\n";
}
I also tried to introduce one exception class per call (read_cfg_exception,
operation1_exception, operation2_exception). Since in read_cfg() the call to
open might throw, I catch its exception and convert it to a
read_cfg_exception, thereby saving the additional information, that something
whent wrong "while reading configuration". Yet this does not feel right either:
class read_cfg_exception;
void open(std::string name); // might throw std::runtime_error
void read_cfg()
{
try {
open("foo.cfg");
}
catch (std::runtime_error& e) {
throw read_cfg_exception(e.what() + "while reading configuration");
}
}
Therefor I have the question: What is a good pattern to show the additional
information of what the program was doing while the error occured.
take a look at POCO (c++ library) throwing system, that should answer all your questions, you'll learn a lot from that and many good style rules too. The answare to your question will be really long unfortunately (at least I don't know how to make it short).
Anyway don't implement something that makes your code not readable, in your example code is not readable and then not maintainable wich is not wanted.

Global exception handling in C++

Can i implement global exception handling in C++?
My requirement is try...catch block is not used in a piece of code then there should be a global exception handler which will handle all uncaught exception.
Can i achieve it, please give your valuable suggestion : )
I always wrap the outer-most function in a try-catch like this:
int main()
{
try {
// start your program/function
Program program; program.Run();
}
catch (std::exception& ex) {
std::cerr << ex.what() << std::endl;
}
catch (...) {
std::cerr << "Caught unknown exception." << std::endl;
}
}
This will catch everything. Good exception handling in C++ is not about writing try-catch all over, but to catch where you know how to handle it (like you seem to want to do). In this case the only thing to do is to write the error message to stderr so the user can act on it.
you can use a combination of set_terminate and current_exception()
i wanted to do the same, here's what i came up with
std::set_terminate([]() -> void {
std::cerr << "terminate called after throwing an instance of ";
try
{
std::rethrow_exception(std::current_exception());
}
catch (const std::exception &ex)
{
std::cerr << typeid(ex).name() << std::endl;
std::cerr << " what(): " << ex.what() << std::endl;
}
catch (...)
{
std::cerr << typeid(std::current_exception()).name() << std::endl;
std::cerr << " ...something, not an exception, dunno what." << std::endl;
}
std::cerr << "errno: " << errno << ": " << std::strerror(errno) << std::endl;
std::abort();
});
in addition to checking what(), it also checks ernno/std::strerror() - in the future i intend to add stack traces as well through exeinfo/backtrace() too
the catch(...) is in case someone threw something other than exception.. for example throw 1; (throw int :| )
In C++ the terminate function is called when an exception is uncaught. You can install your own terminate handler with the set_terminate function. The downside is that your terminate handler may never return; it must terminate your program with some operating system primitive. The default is just to call abort()
When an exception is raised, if is not caught at that point, it goes up the hierarchy until it is actually caught. If there is no code to handle the exception the program terminates.
You can run specific code before termination to do cleanup by using your own handlers of set_unexpected or set_terminate