Advanced I/O & Exception Handling
Slides version: lecture15_slides.html Website version: lecture15.html
- Detail in
iostream
,fstream
&stringstream
- Stream Operator & Manipulator
- Stream Status & Error Handling
- Exception & Exception Handling
- What is an exception?
- How to handle exceptions?
- How many types of exceptions?
std::exception
class
iostream
,fstream
& exception handling
- Example: Exception Handling,
iostream
&fstream
Error Handling - Practices
Stream Operator & Manipulator
<<
& >>
stream operator
Discussed in lecture14
Stream Manipulator
Ref: Manipulators in C++ with Examples
There are two types of manipulators in C++:
- Manipulators without arguments:
- endl (output
\n
and flush), ws (consume whitespace), ends (output\0
), flush (flush output buffer to terminal)
- endl (output
- Manipulators with Arguments: Some of the manipulators are used with the argument like
setw(20)
,setfill(*)
, and many more.
- In
<ios>
:(no)boolalpha
,(no)uppercase
,(no)showbase
,(no)showpos
,(no)showpoint
,(no)skipws
,(no)unitbuf
,internal
,left
,right
,hex
,dec
,oct
,fixed
,scientific
- In
<iomanip>
:setw(val)
,setfill(c)
,setprecision(val)
,setbase(val)
,setiosflags(flag)
,resetiosflags(m)
(no)boolalpha
Ref: std::boolalpha, std::noboolalpha
#include <sstream>
#include <iostream>
int main()
{
// boolalpha output
std::cout << std::boolalpha
<< "boolalpha true: " << true << '\n'
<< "boolalpha false: " << false << '\n';
std::cout << std::noboolalpha
<< "noboolalpha true: " << true << '\n'
<< "noboolalpha false: " << false << '\n';
// boolalpha parse
bool b1, b2;
std::istringstream is("true false");
is >> std::boolalpha >> b1 >> b2;
std::cout << '\"' << is.str() << "\" parsed as " << b1 << ' ' << b2 << '\n';
}
(no)uppercase
, (no)showbase
Ref: std::showbase, std::noshowbase, std::uppercase, std::nouppercase
#include <sstream>
#include <locale>
#include <iostream>
#include <iomanip>
int main()
{
// showbase affects the output of octals and hexadecimals
std::cout << std::hex
<< "showbase: " << std::showbase << 42 << '\n'
<< "noshowbase: " << std::noshowbase << 42 << '\n';
// uppercase affects the output of hexadecimals
std::cout << std::hex << std::showbase
<< "0x2a with uppercase: " << std::uppercase << 0x2a << '\n'
<< "0x2a with nouppercase: " << std::nouppercase << 0x2a << '\n'
<< "1e-10 with uppercase: " << std::uppercase << 1e-10 << '\n'
<< "1e-10 with nouppercase: " << std::nouppercase << 1e-10 << '\n';
}
(no)showpos
, (no)showpoint
Ref: std::showpos, std::noshowpos, std::showpoint, std::noshowpoint
#include <iostream>
int main()
{
std::cout << "1.0 with showpoint: " << std::showpoint << 1.0 << '\n'
<< "1.0 with noshowpoint: " << std::noshowpoint << 1.0 << '\n';
std::cout
<< "showpos: " << std::showpos << 42 << ' ' << 3.14 << ' ' << 0 << '\n'
<< "noshowpos: " << std::noshowpos << 42 << ' ' << 3.14 << ' ' << 0 << '\n';
}
(no)skipws
Ref: std::skipws, std::noskipws
#include <iostream>
#include <sstream>
int main()
{
char c1, c2, c3;
std::istringstream("a b c") >> c1 >> c2 >> c3;
std::cout << "Default behavior: c1 = " << c1 << " c2 = " << c2 << " c3 = " << c3 << '\n';
std::istringstream("a b c") >> std::noskipws >> c1 >> c2 >> c3;
std::cout << "noskipws behavior: c1 = " << c1 << " c2 = " << c2 << " c3 = " << c3 << '\n';
}
internal
, left
, right
Ref: std::left, std::right, std::internal
#include <iostream>
#include <iomanip>
#include <locale>
int main()
{
std::cout.imbue(std::locale("en_US.utf8"));
std::cout << "Default positioning:\n"
<< std::setfill('*')
<< std::setw(12) << -1.23 << '\n'
<< std::setw(12) << std::hex << std::showbase << 42 << '\n'
<< std::setw(12) << std::put_money(123, true) << "\n\n";
std::cout << "Left positioning:\n"
<< std::left
<< std::setw(12) << -1.23 << '\n'
<< std::setw(12) << 42 << '\n'
<< std::setw(12) << std::put_money(123, true) << "\n\n";
std::cout << "Internal positioning:\n"
<< std::internal
<< std::setw(12) << -1.23 << '\n'
<< std::setw(12) << 42 << '\n'
<< std::setw(12) << std::put_money(123, true) << "\n\n";
std::cout << "Right positioning:\n"
<< std::right
<< std::setw(12) << -1.23 << '\n'
<< std::setw(12) << 42 << '\n'
<< std::setw(12) << std::put_money(123, true) << '\n';
}
hex
, dec
, oct
Ref: std::dec, std::hex, std::oct
#include <iostream>
#include <sstream>
#include <bitset>
int main()
{
std::cout << "The number 42 in octal: " << std::oct << 42 << '\n'
<< "The number 42 in decimal: " << std::dec << 42 << '\n'
<< "The number 42 in hex: " << std::hex << 42 << '\n';
int n;
std::istringstream("2A") >> std::hex >> n;
std::cout << std::dec << "Parsing \"2A\" as hex gives " << n << '\n';
// the output base is sticky until changed
std::cout << std::hex << "42 as hex gives " << 42
<< " and 21 as hex gives " << 21 << '\n';
// Note: there is no I/O manipulator that sets up a stream to print out
// numbers in binary format (e.g. bin). If binary output is necessary
// the std::bitset trick can be used:
std::cout << "The number 42 in binary: " << std::bitset<8>{42} << '\n';
}
fixed
, scientific
Ref: std::fixed, std::scientific
#include <iostream>
#include <iomanip>
#include <sstream>
enum class cap { title, middle, end };
void print(const char* text, double num, cap c)
{
if (c == cap::title) std::cout <<
"┌──────────┬────────────┬──────────────────────────┐\n"
"│ number │ iomanip │ representation │\n"
"├──────────┼────────────┼──────────────────────────┤\n"
;
std::cout << std::left
<< "│ " << std::setw(8) << text << " │ fixed │ "
<< std::setw(24) << std::fixed << num << " │\n"
<< "│ " << std::setw(8) << text << " │ scientific │ "
<< std::setw(24) << std::scientific << num << " │\n"
<< "│ " << std::setw(8) << text << " │ hexfloat │ "
<< std::setw(24) << std::hexfloat << num << " │\n"
<< "│ " << std::setw(8) << text << " │ default │ "
<< std::setw(24) << std::defaultfloat << num << " │\n"
;
std::cout << (c != cap::end ?
"├──────────┼────────────┼──────────────────────────┤\n" :
"└──────────┴────────────┴──────────────────────────┘\n" );
}
int main()
{
print("0.0", 0.0, cap::title);
print("0.01", 0.01, cap::middle);
print("0.00001", 0.00001, cap::end);
// Note; choose clang for correct output
double f;
std::istringstream("0x1.8p+0") >> f;
std::cout << "Parsing 0x1.8p+0 gives " << f << '\n';
std::istringstream("0x1P-1022") >> f;
std::cout << "Parsing 0x1P-1022 gives " << f << '\n';
}
setw(val)
, setfill(c)
Ref: std::setw, std::setfill
#include <sstream>
#include <iostream>
#include <iomanip>
int main()
{
std::cout << "default fill: [" << std::setw(10) << 42 << "]\n"
<< "setfill('*'): [" << std::setfill('*')
<< std::setw(10) << 42 << "]\n";
std::cout << "no setw: [" << 42 << "]\n"
<< "setw(6): [" << std::setw(6) << 42 << "]\n"
<< "setw(6), several elements: [" << 89 << std::setw(6) << 12 << 34 << "]\n";
std::istringstream is("hello, world");
char arr[10];
is >> std::setw(6) >> arr;
std::cout << "Input from \"" << is.str() << "\" with setw(6) gave \""
<< arr << "\"\n";
}
setprecision(val)
Ref: std::setprecision
#include <iostream>
#include <iomanip>
#include <cmath>
#include <limits>
int main()
{
const long double pi = std::acos(-1.L);
std::cout << "default precision (6): " << pi << '\n'
<< "std::setprecision(10): " << std::setprecision(10) << pi << '\n'
<< "max precision: "
<< std::setprecision(std::numeric_limits<long double>::digits10 + 1)
<< pi << '\n';
}
setbase(val)
, alias of std::oct
, std::dec
, std::hex
Ref: std::setbase
#include <iostream>
#include <sstream>
#include <iomanip>
int main()
{
std::cout << "Parsing string \"10 0x10 010\"\n";
int n1, n2, n3;
std::istringstream s("10 0x10 010");
s >> std::setbase(16) >> n1 >> n2 >> n3;
std::cout << "hexadecimal parse: " << n1 << ' ' << n2 << ' ' << n3 << '\n';
s.clear();
s.seekg(0);
s >> std::setbase(0) >> n1 >> n2 >> n3;
std::cout << "prefix-dependent parse: " << n1 << ' ' << n2 << ' ' << n3 << '\n';
std::cout << "hex output: " << std::setbase(16)
<< std::showbase << n1 << ' ' << n2 << ' ' << n3 << '\n';
}
setiosflags(flag)
, resetiosflags(m)
Ref: std::setiosflags, std::resetiosflags
#include <sstream>
#include <iostream>
#include <iomanip>
int main()
{
if (false)
{
std::cout << std::resetiosflags(std::ios_base::dec)
<< std::setiosflags(std::ios_base::hex | std::ios_base::uppercase | std::ios_base::showbase) << 42 << '\n';
}
else
{
std::istringstream in("10 010 10 010 10 010");
int n1, n2;
in >> std::oct >> n1 >> n2;
std::cout << "Parsing \"10 010\" with std::oct gives: " << n1 << ' ' << n2 << '\n';
in >> std::dec >> n1 >> n2;
std::cout << "Parsing \"10 010\" with std::dec gives: " << n1 << ' ' << n2 << '\n';
in >> std::resetiosflags(std::ios_base::basefield) >> n1 >> n2;
std::cout << "Parsing \"10 010\" with autodetect gives: " << n1 << ' ' << n2 << '\n';
}
}
Stream Status & Error Handling
Ref: std::basic_ios, std::ios_base::iostate
- 4 states:
.good()
,.eof()
,.fail()
,.bad()
.good()
: checks if no error has occurred i.e. I/O operations are available..eof()
: checks if end-of-file has been reached..fail()
: checks if an error has occurred..bad()
: checks if a non-recoverable error has occurred.
all of them are based on ios_base::iostate
badbit
:true
if the stream has an irrecoverable stream erroreofbit
:true
if the stream's associated input sequence has reached end-of-filefailbit
:true
if the stream has an input/output operation failed (formatting or extraction error)
When will badbit
be set
The badbit is set by the following situations:
- Fails to insert a character into the output stream, for any reason.
operator<<
encounter the end of the output stream before completing output.- Initialize a stream with a
NULL
pointer. - called on a stream with a
NULL
pointer buffer. - A
NULL
pointer is passed as the argument. - Buffer opeartions are returned with EOF value.
- Every stream I/O function if an exception is thrown by any member function of the associated stream buffer.
- Failure to allocate memory.
When will eofbit
be set
The eofbit is set by the following situations:
- Reaching the end of the stream, as opposed to reaching the specified terminating character.
When will failbit
be set
The failbit is set by the following situations:
- Initialize a stream while the stream either
eofbit
orbadbit
is set. - Extract invalid characters/invalid format/no characters or extract a
NULL
pointer. - Extract
basic_string::max_size
characters from the input stream. - If the end-of-file condition occurs on the input stream before all requested characters could be extracted.
seekg
ortellp
on failure- The constructors of
fstream
,ifstream
, andofstream
that takes a filename argument, if the file cannot be opened. fstream::open
,ifstream::open
, andofstream::open
if the file cannot be opened.fstream::close
,ifstream::close
, andofstream::close
if the file cannot be closed.
Relation between iostate
flags and stream status
eofbit | failbit | badbit | .good() | .fail() | .bad() | .eof() | operator bool() | operator!() |
---|---|---|---|---|---|---|---|---|
false | false | false | true | false | false | false | true | false |
false | false | true | false | true | true | false | false | true |
false | true | false | false | true | false | false | false | true |
false | true | true | false | true | true | false | false | true |
true | false | false | false | false | false | true | true | false |
true | false | true | false | true | true | true | false | true |
true | true | false | false | true | false | true | false | true |
true | true | true | false | true | true | true | false | true |
Exception & Exception Handling
- What is an exception?
- How to handle exceptions?
- How many types of exceptions?
iostream
,fstream
& exception handling
What is an exception?
Ref: Exception Handling in C++
Exceptions are run-time anomalies or abnormal conditions that a program encounters during its execution. There are two types of exceptions: a) Synchronous b) Asynchronous (Ex: which are beyond the program's control, Disc failure etc).
How to handle exceptions?
In C++, exceptions are handled by the following statements:
try
{
// a exception variable, could be any type
// and could be used without declaration
exception_type e;
// statements to be executed
// if exception occurs, throw the exception
throw e;
}
catch (exception_type e)
{
// statements to handle any exception thrown
}
Example:
#include <iostream>
using namespace std;
int main()
{
int x = -1;
// Some code
cout << "Before try \n";
try
{
cout << "Inside try \n";
if (x < 0)
{
throw x;
cout << "After throw (Never executed) \n";
}
}
catch (int x)
{
cout << "Exception Caught \n";
}
cout << "After catch (Will be executed) \n";
return 0;
}
Example: multiple catch blocks & default catch block
#include <iostream>
using namespace std;
int main()
{
try
{
throw 10;
}
catch (char *excp)
{
cout << "Caught " << excp;
}
catch (...)
{
cout << "Default Exception\n";
}
return 0;
}
Example: uncaught exception
#include <iostream>
using namespace std;
int main()
{
try
{
// error, unhandled exception
throw 'a';
}
catch (int x)
{
cout << "Caught ";
}
return 0;
}
Example: Nesting of exceptions
#include <iostream>
using namespace std;
int main()
{
try
{
try
{
throw 20;
}
catch (int n)
{
cout << "Handle Partially ";
throw; // Re-throwing an exception
}
}
catch (int n)
{
cout << "Handle remaining ";
}
return 0;
}
Example: class & exception
#include <iostream>
using namespace std;
class Test
{
public:
Test() { cout << "Constructor of Test " << endl; }
~Test() { cout << "Destructor of Test " << endl; }
};
int main()
{
try
{
Test t1;
throw 10;
}
catch (int i)
{
cout << "Caught " << i << endl;
}
}
Example: class inheritance & exception
// C++ Program to demonstrate a catching of
// Derived exception and printing it successfully
#include <iostream>
using namespace std;
class Base
{
};
class Derived : public Base
{
};
int main()
{
Derived d;
// Some other functionalities
try
{
// Monitored code
throw d;
}
catch (Derived d)
{
// the derived class object should be caught before the base class object
// else the base class object will always be caught
cout << "Caught Derived Exception";
}
catch (Base b)
{
cout << "Caught Base Exception";
}
getchar(); // To read the next character
return 0;
}
How many types of exceptions?
There are three types of exceptions:
- any preliminary types (e.g.,
int
,char
,float
, etc.)- Discussed in the previous section
- user-defined types (e.g.,
class
,struct
, etc.)- Discussed in the previous section
std::exception
std::exception
Ref: Exception header in C++ with examples
std::exception
is the base class of all exceptions in C++ standard library.
Exception | Description |
---|---|
std::bad_alloc | Memory allocation failed |
std::bad_cast | Invalid type conversion |
std::bad_exception | Exception handling failed |
std::bad_typeid | Invalid typeid |
std::bad_function_call | Invalid function call |
std::bad_weak_ptr | Invalid weak pointer |
std::logic_error | Logic error |
std::runtime_error | Runtime error |
exception::what()
Ref: exception::what() in C++ with Examples
To get the description of the exception, use the what()
member function.
The example below shows how to use the what()
member function and how it works.
// C++ code for exception::what()
#include <iostream>
#include <exception>
using namespace std;
class geeksforgeeks : public exception
{
public:
const char *what() const noexcept
{
return "Hey!!";
}
};
// main method
int main()
{
// try block
try
{
throw geeksforgeeks();
}
// catch block to handle the errors
catch (exception &gfg)
{
cout << gfg.what();
}
return 0;
}
Example: std::bad_alloc
// C++ program to illustrate bad_alloc
// using class bad_alloc
#include <exception>
#include <iostream>
using namespace std;
// Function to illustrate bad_alloc
void createArray(long long N)
{
// Try Block
try
{
// Create an array of length N
int *array = new int[N];
// If created successfully then
// print the message
cout << "Array created successfully"
<< " of length " << N << " \n";
}
// Check if the memory
// was allocated or not
// using class bad_alloc
catch (bad_alloc &e)
{
// If not, print the error message
cout << e.what()
<< " for array of length "
<< N << " \n";
}
}
// Driver Code
int main()
{
// Function call to create an
// array of 1000 size
createArray(1000);
// Function call to create an
// array of 1000000000 size
createArray(10000000000);
return 0;
}
Example: std::logic_error
// C++ program to illustrate logic_error
#include <exception>
#include <iostream>
using namespace std;
// Function to find factorial of N and
// throws error if occurs
void findFactorial(int N)
{
// Initialise variable by 1
int factorial = 1;
// Check for errors
try
{
// If N is less than zero then,
// it shows errors as factorial
// of negative number can't be
// calculated
if (N < 0)
{
// Exception object which
// returns the message passed
// to it
throw invalid_argument(
"negative not allowed");
}
// Find factorial if no error occurs
for (int i = N; i > 0; i--)
{
factorial *= i;
}
cout << "Factorial of " << N
<< " is " << factorial << endl;
}
// Print the error message
catch (exception &e)
{
cout << e.what();
}
}
// Driver Code
int main()
{
// Function call to find factorial
// of 0
findFactorial(0);
// Function call to find factorial
// of 3
findFactorial(3);
// Function call to find factorial
// of -1
findFactorial(-1);
return 0;
}
Example: Divide by zero
Ref: Handling the Divide by Zero Exception in C++
// Program to depict how to handle
// divide by zero exception
#include <iostream>
#include <stdexcept> // To use runtime_error
using namespace std;
// Defining function Division
float Division(float num, float den)
{
// If denominator is Zero
// throw runtime_error
if (den == 0)
{
throw runtime_error("Math error: Attempted to divide by Zero\n");
}
// Otherwise return the result of division
return (num / den);
} // end Division
int main()
{
float numerator, denominator, result;
numerator = 12.5;
denominator = 0;
// try block calls the Division function
try
{
result = Division(numerator, denominator);
// this will not print in this example
cout << "The quotient is "
<< result << endl;
}
// catch block catches exception thrown
// by the Division function
catch (runtime_error &e)
{
// prints that exception has occurred
// calls the what function
// using runtime_error object
cout << "Exception occurred" << endl
<< e.what();
}
} // end main
iostream
, fstream
& exception handling
Ref: std::basic_ios::exceptions
To Handle stream .bad()
, .fail()
and .eof()
flags with try ... catch
block, use .exceptions()
member function to set the exceptions to be thrown.
The type of exception thrown is ios_base::failure
.
Example:
#include <iostream>
#include <fstream>
int main()
{
int ivalue;
try
{
std::ifstream in("in.txt");
in.exceptions(std::ifstream::failbit); // may throw
in >> ivalue; // may throw
}
catch (const std::ios_base::failure &fail)
{
// handle exception here
std::cout << fail.what() << '\n';
}
}
Example: Exception Handling, iostream
& fstream
Error Handling [Source]
Practices
- Try to read/write files in serveral stream formats.
std::string
,std::hex
,std::uppercase
, etc.
- Try to handle errors in
std::fstream
andstd::iostream
- fail to open file, read/write error, invalid format, etc.
- Try to throw/handle exceptions in user-defined class
- examples in lectrue 2 to lecture 12