
catch, the declaration of a single type or single object within parentheses (referred to as an exception declaration), and a set of statements within a compound statement.After a catch clause has completed its work, the execution of the program continues at the statement that follows the last catch clause in the list.
#include <vector>
#include <iostream>
template<class T> class pushOnFull;
template<class T> class popOnEmpty;
template<class T>
class Stack {
public:
Stack(int len) : _len(len) {}
void push( const T& e );
void pop();
int len() { return _len; }
private:
std::vector<T> vec;
int _len;
};
template<class T>
void Stack<T>::push( const T& e ){
if ( vec.size() >= _len ){
throw pushOnFull<T>(e);
}
vec.emplace_back(e);
}
template<class T>
void Stack<T>::pop(){
if ( vec.size() == 0 ){
throw popOnEmpty<T>();
}
vec.pop_back();
}
template<class T>
class pushOnFull {
public:
pushOnFull(T value) : _val(value){}
int value() { return _val; }
private:
T _val;
};
template<class T>
class popOnEmpty {
public:
popOnEmpty() = default;
};
int main()
{
try {
Stack<float>* s = new Stack<float>(2);
s->push(3.0f);
s->push(2.0f);
s->push(1.0f);
return 0;
}
catch ( popOnEmpty<float>& e){
std::cerr << "Pop on empty stack!\n";
}
catch ( pushOnFull<float>& e ){
std::cerr << "Push " << e.value() << " on full stack!\n";
}
catch (...) {
}
std::cerr << "Finished the program\n";
}
#include <iostream>
struct ErrorCode {
int code;
ErrorCode(int c) : code(c) {
std::cout << "ErrorCode: constructor called. this: " << this << "\n";
}
ErrorCode(const ErrorCode& other) : code(other.code) {
std::cout << "ErrorCode: copy constructor called. this: " << this << "\n";
}
~ErrorCode() {
std::cout << "ErrorCode: destructor called. this: " << this << "\n";
}
};
void mathFunc(int i) {
if (i == 0) {
throw ErrorCode(42); // calls ctor for temporary object
// calls copy ctor for exception object
} // calls destructor for the temporary object
}
int main() {
try {
mathFunc(0);
} catch (ErrorCode& e) {
std::cout << "Caught error with code = " << e.code << "\n";
} // calls destructor for the exception object
}
# g++ main.cc -std=c++98
# g++ main.cc -fno-elide-constructors -std=c++11 (without copy elision):
ErrorCode: constructor called. this: 0x7ffe289f4704
ErrorCode: copy constructor called. this: 0x5558d90d8f30
ErrorCode: destructor called. this: 0x7ffe289f4704
Caught error with code = 42
ErrorCode: destructor called. this: 0x5558d90d8f30
# g++ main.cc (with copy elision, mandatory from C++11)
ErrorCode: constructor called. this: 0x565312d1ef30
Caught error with code = 42
ErrorCode: destructor called. this: 0x565312d1ef30
#include <iostream>
struct ErrorCode {
int code;
ErrorCode(int c) : code(c) {
std::cout << "ErrorCode: constructor called. this: " << this << "\n";
}
ErrorCode(const ErrorCode& other) : code(other.code) {
std::cout << "ErrorCode: copy constructor called. this: " << this << "\n";
}
~ErrorCode() {
std::cout << "ErrorCode: destructor called. this: " << this << "\n";
}
};
void mathFunc(int i) {
if (i == 0) {
ErrorCode err(42); // calls ctor for object A
throw err; // calls copy ctor for object B
} // calss destructor for object A
}
int main() {
try {
mathFunc(0);
} catch (ErrorCode& e) {
std::cout << "Caught error with code = " << e.code << "\n";
} // calls destructor for object B
}
So calling constructor at throw point is more efficient.
#include <iostream>
struct ErrorCode {
int code;
ErrorCode(int c) : code(c) {
std::cout << "ErrorCode: constructor called. this: " << this << "\n";
}
ErrorCode(const ErrorCode& other) : code(other.code) {
std::cout << "ErrorCode: copy constructor called. this: " << this << "\n";
}
~ErrorCode() {
std::cout << "ErrorCode: destructor called. this: " << this << "\n";
}
};
void mathFunc(int i) {
if (i == 0) {
ErrorCode err(42); // calls ctor for object A
throw err; // calls copy ctor for object B
} // calss destructor for objects A
}
int main() {
try {
mathFunc(0);
} catch (ErrorCode e) { // calls copy ctor for object C
std::cout << "Caught error with code = " << e.code << "\n";
} // calls destructor for objects C and B in turn
}
#include <iostream>
struct ErrorCode {
ErrorCode(int c) : code(c) {
std::cout << "ErrorCode: constructor called. this: " << this << "\n";
}
ErrorCode(const ErrorCode& other) : code(other.code) {
std::cout << "ErrorCode: copy constructor called. this: " << this << "\n";
}
~ErrorCode() {
std::cout << "ErrorCode: destructor called. this: " << this << "\n";
}
int code;
};
ErrorCode g_e(2); // calls ctor for g_e
void mathFunc(int i) {
if (i == 0) {
throw g_e; // calls copy ctor for copied g_e
}
}
int main() {
try {
mathFunc(0);
} catch (ErrorCode &e) {
std::cout << "code = " << e.code << "\n"; // 2
e.code = 3;
std::cout << "code = " << e.code << "\n"; // 3
} // calls destructor for copied g_e
std::cout << "code = " << g_e.code << "\n"; // 2
} // calls destructor for g_e
#include <iostream>
class Tracker {
public:
Tracker( const std::string& name ) : _name(name)
{ std::cout << "calls ctor " << _name << "\n"; }
~Tracker() { std::cout << "calls destructor " << _name << "\n"; }
private:
std::string _name;
};
void level3(){
Tracker t3("in level 3");
throw std::runtime_error("Exception thrown in level3");
}
void level2(){
Tracker t2("in level 2");
level3();
}
void level1(){
Tracker t1("in level 1");
level2();
}
int main(){
try {
level1();
} catch (const std::exception& e) {
std::cout << "Caught exception: " << e.what() << std::endl;
}
}
terminate() function defined in the C++ standard library. The default behavior of terminate() is to call abort(), indicating the abnormal exit from the program.terminate() function exists: it is a run-time mechanism to tell users when no handler matches the exception thrown. #include <iostream>
#include <stdexcept> // for std::runtime_error
struct ErrorCode {
ErrorCode(int c) : code(c) {
std::cout << "ErrorCode: constructor called. this: " << this << "\n";
}
ErrorCode(const ErrorCode& other) : code(other.code) {
std::cout << "ErrorCode: copy constructor called. this: " << this << "\n";
}
~ErrorCode() {
std::cout << "ErrorCode: destructor called. this: " << this << "\n";
}
int code;
};
void inner () {
std::cout << "Calls inner()\n";
throw ErrorCode(0); // ctor for object A
}
void outer () {
try {
std::cout << "Calls outer()\n";
inner();
} catch ( const ErrorCode& e ) {
std::cout << "Intermediate hadler: code = " << e.code << "\n";
// Doing partial handling, then rethrowing...
throw;
}
}
int main(){
try {
outer();
} catch ( const ErrorCode& e ) {
std::cout << "Final handler: code = " << e.code << "\n";
}
}
Calls outer()
Calls inner()
ErrorCode: constructor called. this: 0x5569787fd340
Intermediate hadler: code = 0
Final handler: code = 0
ErrorCode: destructor called. this: 0x5569787fd340
catch(...) is used in combination with a rethrow expression.
#include <iostream>
#include <stdexcept>
class Resource {
public:
Resource() { std::cout << "Resource acquired.\n"; }
~Resource() { std::cout << "Resource released.\n"; }
};
void riskyFunction() {
Resource* res = new Resource();
try {
std::cout << "riskyFunction(): Doing something risky...\n";
throw std::runtime_error("Boom! Something went wrong.");
} catch (...) {
std::cout << "riskyFunction(): Exception caught. Cleaning up before rethrow.\n";
delete res; // Manual cleanup (if not using RAII)
throw; // Rethrow current exception
}
}
int main() {
try {
riskyFunction();
} catch (const std::exception& e) {
std::cout << "main(): Exception handled: " << e.what() << "\n";
}
return 0;
}
catch (...) is used in combination with other catch clauses, it must always be placed last in a list of exception handlers; otherwise, a compiler error is issued.