In which cases do Options 1 and 2 give different results/behaviour?
Are they equivalent in all respects?
I tried with a non-existing in_out/sample2.txt to force an exception and they behave the same.
int main() {
string fnamein2 = "in_out/sample2.txt";
ifstream ifstr;
try {
cout << "Reading " << fnamein2 << endl;
ifstr.open(fnamein2);
ifstr.exceptions( ifstream::eofbit | ifstream::failbit | ifstream::badbit );
} catch(const exception &e) { // <-- Option 1
//} catch(const ifstream::failure &e) { // <-- Option 2
cout << "There was an error: " << e.what() << endl;
}
return 0;
}
There is no difference in your scenario.
std::ifstream::failure is specialized version of std::exception (contains more details) but in your case you do not used them.
std::ifstream::failure has code method which gives you more information about an error. But if you do not need it, you can use base class.
Related
<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.
Consider this code:
int main()
{
try
{
throw std::range_error("");
}
catch (std::bad_alloc)
{
std::cout << "AAAA" << std::endl;
throw;
}
catch (std::range_error)
{
std::cout << "BBB" << std::endl;
throw;
}
catch (std::exception)
{
std::cout << "CCC" << std::endl;
}
std::cout << "DDD" << std::endl;
}
Here I throw an exception of type std::range_error and trying to catch it.
Logically the first catch block cannot catch it because of type mismatch(std::bad_alloc and std::range_error).
The second catch block must catch it because they are the same types of std::range_error.
And also, when I rethrow the exception in second catch block it must be caught in the third catch block.
So my output must be
BBB
CCC
DDD
But I only get the BBB output with the termination.
Can anybody please explain me the behavior??
When you re-throw an exception, you are throwing it completely out of the context of the current exception handling block.... So,
try
{
throw std::range_error("");
}
catch (std::bad_alloc)
{
std::cout << "AAAA" << std::endl;
throw;
}
catch (std::range_error)
{
std::cout << "BBB" << std::endl;
throw;
}
catch (std::exception)
{
std::cout << "CCC" << std::endl;
}
is one exception handling block. Therefore, on meeting the first throw in any of the catch blocks, it leaves the whole block to look for another handling block (try-catch) outside the current scope. if not found, the program terminates.
Please see try-catch block in C++
To print as you initially thought ... Live On Coliru ...
int main()
{
try{
try{
try{
throw std::range_error("");
}
catch (std::bad_alloc) {
std::cout << "AAAA" << std::endl;
throw;
}
}
catch (std::range_error) {
std::cout << "BBB" << std::endl;
throw;
}
}
catch (std::exception){
std::cout << "CCC" << std::endl;
}
std::cout << "DDD" << std::endl;
}
Prints:
BBB
CCC
DDD
For the record: please avoid using exceptions for control flow that could be done with simple if-else ladder in production code
To re-catch the range_error and new outer try catch block is required.
#include <iostream>
int main()
{
//outer try catch ------------------------
try {
// inner try catch ---------------------
try
{
throw std::range_error("");
}
catch (std::bad_alloc)
{
std::cout << "AAAA" << std::endl;
throw;
}
catch (std::range_error)
{
std::cout << "BBB" << std::endl;
throw;
}
// -------------------------------
}
catch (std::exception)
{
std::cout << "CCC" << std::endl;
}
// --------------------------------
std::cout << "DDD" << std::endl;
}
Output
BBB
CCC
DDD
This throw:
catch (std::range_error)
{
std::cout << "BBB" << std::endl;
throw; // <== this one
}
isn't itself within the body of a try, so when the exception handling mechanism will keep going out one scope at a time until it finds one. Since there is no other outer try, the exception isn't caught at all.
There is no reentrance in exception handling.
I open two files, one input and one output. I'd like to handle exceptions for both of them, so by looking at some examples, I made this:
std::ifstream readFile;
readFile.exceptions (std::ifstream::failbit | std::ifstream::badbit);
//set the flags for stream bits that indicate failure if ON
std::ofstream writeFile;
writeFile.exceptions (std::ifstream::failbit | std::ifstream::badbit);
try{
readFile.open(inputFileName);
writeFile.open(outputFileName);
function(readFile, writeFile);
readFile.close();
writeFile.close();
}
catch(std::ifstream::failure &readErr) {
std::cerr << "\n\nException occured when reading a file\n"
<< readErr.what()
<< std::endl;
return -1;
}
catch(std::ofstream::failure &writeErr) {
std::cerr << "\n\nException occured when writing to a file\n"
<< writeErr.what()
<< std::endl;
return -1;
}
This seems like a reasonable solution, but I get a warning:
warning: exception of type 'std::ios_base::failure' will be caught [enabled by default]
catch(std::ofstream::failure &writeErr) {
^
The code does it's thing, but I'm still interested in improving my code. Where have I wronged?
No you can't. The typedef of std::ifstream::failure and std::ofstream::failure are both defined to be std::ios_base::failure.
The best thing you could do is wrap the individual calls with try-catch:
try
{
readFile.open(inputFileName);
}
catch(std::ifstream::failure &readErr)
{
}
try
{
writeFile.open(outputFileName);
}
catch(std::ofstream::failure &writeErr)
{
}
Or check the state of the streams individually in the catch block to see who failed.
The only way to handle exceptions from the two files separately would be to catch the exception and then check the failbit on the streams to determine which of them that failed:
try
{
readFile.open(inputFileName);
writeFile.open(outputFileName);
function(readFile, writeFile);
readFile.close();
writeFile.close();
}
catch (const std::ios_base::failure &err)
{
if (readFile.fail())
{
std::cerr << "\n\nException occured when reading a file\n"
<< readErr.what()
<< std::endl;
}
if (writeFile.fail())
{
std::cerr << "\n\nException occured when writing to a file\n"
<< writeErr.what()
<< std::endl;
}
return -1;
}
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.
Could you guys help me decypher unknown exception that is thrown by boost::iostreams::mapped_file_sink ?
My configuration
boost 1.51
Visual Studio 2012 on Windows 7
GCC 4.7 on Ubuntu
Here is the code I have
try
{
boost::iostreams::mapped_file_params params_;
boost::iostreams::mapped_file_sink sink_;
params_.length = 0;
params_.new_file_size = 1024;
params_.path = "./test.bin";
sink_.open(params_);
sink_.close();
}
catch (std::ios::failure& ex)
{
std::cout << "\t" << "what: " << ex.what() << "\n";
}
catch (std::system_error& ex)
{
std::cout << "\t" << "code: " << ex.code() << " what: " << ex.what() << "\n";
}
catch (std::runtime_error& ex)
{
std::cout << "\t" << ex.what() << "\n";
}
catch (boost::archive::archive_exception& ex)
{
std::cout << "\t" << ex.what() << "\n";
}
catch (boost::exception& ex)
{
std::cout << "blah\n";
}
catch (std::exception& ex)
{
std::cout << "\t" << ex.what() << " --- " << typeid(ex).name() << "\n";
}
It always works in Windows.
In Ubuntu it creates empty file of given size but throws exception on open(). Subsequent execution of the code if exists doesn't cause exception.
The worst part is that I can't see the reason of the exception. I can only catch std::exception whose what() returns meaningless "std::exception".
In desperate attempt to find out what's wrong I output typeid(ex).name() which shows
N5boost16exception_detail10clone_implINS0_19error_info_injectorISt9exception
which according to Google means: boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<std::exception> >
Any ideas what's wrong?
You could run the code in a debugger and set a breakpoint in the function which actually throws an exceptions, e.g., __cxa_throw. The name of the function may be different on your system: use nm -po program | less and search for a function containing throw. Set a breakpoint in the one(s) which look most likely as if they are created by the system. If there are only few exceptions being thrown, you can also set a breakpoint into std::exception::exception().
After 50 mins of guessing I found out that problem was in length field. The documentation doesn't say that but its default value has to be -1 as stated in source code
BOOST_STATIC_CONSTANT(size_type, max_length = static_cast<size_type>(-1));
I intuitively assumed that if I set new_file_size to be more than zero it would ignore length.