Applying Exception Handling and Complete
Unit Revision
|
Learning
Objectives After completing this module,
students should be able to: •
Apply exception handling to input validation, constructors,
destructors, templates and resource management. •
Explain RAII and the three levels of exception safety. •
Decide when exceptions are the right tool and when they are not. •
Revise the whole unit (templates and exception handling) with
comparison tables and know the C++ version of each feature. |
1. Applying Exception Handling
Exception handling is useful whenever an operation can fail for reasons
that the code cannot always prevent. The table lists common applications:
|
Application
area |
Possible
exceptions |
Typical
response |
|
Input validation |
Invalid age, negative amount, wrong format |
Report the error and ask again |
|
Arithmetic |
Division by zero, overflow |
Reject the operation; show an error |
|
Arrays and containers |
Index out of range, empty stack, full queue |
Throw out_of_range or a custom exception |
|
File handling |
File not found, read error, no permission |
Show a message; close files; try another file |
|
Dynamic memory |
bad_alloc |
Release other resources; reduce the request or end the
program |
|
Object construction |
Invalid arguments, failure to acquire a resource |
Throw from the constructor; the object is not created |
|
Banking and business logic |
Insufficient funds, invalid account |
Cancel the transaction; leave the data unchanged |
|
Networking and databases |
Timeout, connection lost |
Retry, or translate to a higher-level exception |
1.1 Application: a bank account
A bank account must refuse invalid operations without damaging its own
state. Each check throws a suitable standard exception before the
balance is changed.
Program 6.1: Validation with invalid_argument and runtime_error.
#include <iostream>
#include <stdexcept>
using namespace std;
class BankAccount
{
private:
double
balance;
public:
explicit
BankAccount(double initialBalance)
{
if
(initialBalance < 0)
throw invalid_argument("Initial balance cannot be negative");
balance
= initialBalance;
}
void
withdraw(double amount)
{
if
(amount <= 0)
throw invalid_argument("Withdrawal amount must be positive");
if
(amount > balance)
throw runtime_error("Insufficient account balance");
//
state changes only after all checks
balance
-= amount;
cout
<< "Withdrawal successful." << endl;
}
void
displayBalance() const { cout << "Balance: " << balance
<< endl; }
};
int main()
{
try {
BankAccount account(5000);
account.displayBalance();
account.withdraw(2000);
account.displayBalance();
account.withdraw(5000);
// too much: exception
account.displayBalance();
// not executed
}
catch
(const exception &e) {
cout
<< "Transaction error: " << e.what() << endl;
}
cout
<< "Program completed." << endl;
return 0;
}
Output:
Balance: 5000
Withdrawal successful.
Balance: 3000
Transaction error: Insufficient account balance
Program completed.
•
invalid_argument
(a logic error) is used for values that are never valid; runtime_error for a condition that depends on the current
state (not enough money).
•
The second withdrawal throws; displayBalance()
after it is skipped, and the balance remains 3000.
•
The handler catches the common base exception by reference and prints what().
1.2 Exceptions in constructors
A constructor has no return value, so an exception is the only
clean way to report that an object could not be created. When a constructor
throws:
•
the object is not created; the code never
receives a half-built object;
•
members and base classes that were already
constructed are destroyed, in reverse order of construction;
•
the destructor of the class itself is not
called, because the object never finished construction.
Program 6.2: A member throws during the
construction of the enclosing object.
#include <iostream>
#include <stdexcept>
using namespace std;
class Part
{
const char
*name;
public:
Part(const
char *n, bool fail = false) : name(n)
{
cout
<< "Part " << name << ": constructor";
if
(fail) {
cout << " -> throws" << endl;
throw runtime_error("Part construction failed");
}
cout
<< endl;
}
~Part() {
cout << "Part " << name << ": destructor"
<< endl; }
};
class Machine
{
Part a;
Part b;
Part c;
public:
Machine() :
a("A"), b("B", true), c("C") // b's constructor throws
{
cout
<< "Machine: constructor body" << endl;
}
~Machine()
{ cout << "Machine: destructor" << endl; }
};
int main()
{
try {
Machine
m;
cout
<< "Machine is ready" << endl;
}
catch
(const exception &e) {
cout
<< "Caught: " << e.what() << endl;
}
return 0;
}
Output:
Part A: constructor
Part B: constructor -> throws
Part A: destructor
Caught: Part construction failed

Figure 6.1: Construction
of Machine fails at member b: a is destroyed, c is never created, ~Machine() is
not called.
|
Important: Because ~Machine()
does not run, a resource acquired in the constructor body with a raw new
would be leaked if a later statement throws. Hold each resource in a member
object (such as a smart pointer) that cleans itself up. This idea is
called RAII (Section 1.5). |
1.3 Exceptions and destructors
A destructor runs during normal scope exit and also during stack
unwinding. If a destructor throws while another exception is already being
handled, two exceptions would be active at once and C++ calls terminate(). Therefore destructors must not let
exceptions escape: any operation inside that could throw must be caught
inside the destructor.
Program 6.3: A destructor that is safe
during stack unwinding.
#include <iostream>
#include <stdexcept>
using namespace std;
class Logger
{
public:
Logger() {
cout << "Object created." << endl; }
//
Destructors are implicitly noexcept since C++11 (written for emphasis).
~Logger()
noexcept
{
try {
//
cleanup that could fail is wrapped
cout << "Destructor: cleanup done." << endl;
}
catch
(...) {
//
never let an exception escape from a destructor
}
}
};
int main()
{
try {
Logger
obj;
cout
<< "Throwing an exception." << endl;
throw
runtime_error("Something went wrong");
}
catch
(const exception &e) {
cout
<< "Exception caught: " << e.what() << endl;
}
cout
<< "Program continues." << endl;
return 0;
}
Output:
Object created.
Throwing an exception.
Destructor: cleanup done.
Exception caught: Something went wrong
Program continues.
|
Version Note: C++11:
destructors are implicitly noexcept. If a
destructor does throw, terminate() is called immediately
even without another active exception. In C++98/03 a destructor could throw
(and the program terminated only if this happened during unwinding), but it
was always bad practice. |
1.4 Combining templates and exception handling
Generic code cannot know what values are valid for every type, but it can
detect general violations such as an empty container, an invalid index or a
zero divisor, and report them with exceptions.
Program 6.4: A generic division function.
#include <iostream>
#include <stdexcept>
using namespace std;
template <typename T>
T safeDivide(T a, T b)
{
if (b ==
T{})
throw
invalid_argument("Division by zero");
return a /
b;
}
int main()
{
try {
cout
<< "Integer result : " << safeDivide(10, 2) <<
endl;
cout
<< "Floating result: " << safeDivide(7.5, 2.5) <<
endl;
cout
<< safeDivide(10, 0) << endl;
}
catch
(const exception &e) {
cout
<< "Error: " << e.what() << endl;
}
cout
<< "Program completed." << endl;
return 0;
}
Output:
Integer result : 5
Floating result: 3
Error: Division by zero
Program completed.
T{} is the default (zero) value
of any numeric type T, so b == T{} tests for a zero divisor for both int and double.
The first two calls succeed (10 / 2 = 5, 7.5 / 2.5 = 3); the third throws.
Program 6.5: A safe array class template
that checks the index.
#include <iostream>
#include <stdexcept>
using namespace std;
template <typename T, int SIZE>
class SafeArray
{
private:
T
data[SIZE];
public:
T
&at(int index)
{
if
(index < 0 || index >= SIZE)
throw out_of_range("Invalid array index");
return
data[index];
}
};
int main()
{
SafeArray<int, 3> arr;
try {
arr.at(0) = 10;
arr.at(1) = 20;
arr.at(2) = 30;
cout
<< arr.at(1) << endl;
cout
<< arr.at(5) << endl;
// out of range
}
catch
(const out_of_range &e) {
cout
<< "Array error: " << e.what() << endl;
}
return 0;
}
Output:
20
Array error: Invalid array index
Program 6.6: A generic stack that reports
overflow and underflow with its own exception hierarchy.
#include <iostream>
#include <stdexcept>
#include <string>
using namespace std;
class StackError : public runtime_error
{
public:
explicit
StackError(const string &m) : runtime_error(m) {}
};
class StackOverflow : public StackError
{
public:
StackOverflow() : StackError("Stack overflow") {}
};
class StackUnderflow : public StackError
{
public:
StackUnderflow() : StackError("Stack underflow") {}
};
template <typename T, int SIZE>
class Stack
{
T
arr[SIZE];
int top;
public:
Stack() :
top(-1) {}
void
push(const T &value)
{
if (top
== SIZE - 1)
throw StackOverflow();
arr[++top] = value;
}
T pop()
{
if (top
== -1)
throw StackUnderflow();
return
arr[top--];
}
};
int main()
{
Stack<int, 2> s;
try {
s.push(10);
s.push(20);
int v =
s.pop();
cout
<< "Popped: " << v << endl;
v =
s.pop();
cout
<< "Popped: " << v << endl;
//
underflow: exception thrown here
v =
s.pop();
cout
<< "Popped: " << v << endl;
}
catch
(const StackUnderflow &e) {
cout
<< "Underflow handler: " << e.what() << endl;
}
catch
(const StackError &e) {
cout
<< "Other stack error: " << e.what() << endl;
}
try {
s.push(1);
s.push(2);
s.push(3); // overflow
}
// base
class handler catches both kinds
catch
(const StackError &e) {
cout
<< "StackError handler: " << e.what() << endl;
}
return 0;
}
Output:
Popped: 20
Popped: 10
Underflow handler: Stack underflow
StackError handler: Stack overflow
•
StackOverflow
and StackUnderflow derive from StackError, which derives from runtime_error.
•
The first try
block uses a specific handler for underflow; the second one uses the base
handler StackError and so catches the
overflow.
•
The stack functions throw instead of printing messages:
the stack class does not know how the program wants to react – this is decided
by the handler in the caller.
1.5 Resource management and RAII
RAII (Resource Acquisition Is Initialization) means that a
resource such as memory, a file, a lock or a socket is acquired in the
constructor of an object and released in its destructor. Since local objects
are destroyed during stack unwinding, the resource is released automatically,
whether the function ends normally or by an exception.
Program 6.7: A leak with a raw pointer, and
automatic release with unique_ptr.
#include <iostream>
#include <memory>
#include <stdexcept>
using namespace std;
class Resource
{
int id;
public:
explicit
Resource(int i) : id(i)
{
cout
<< "Resource " << id << " acquired"
<< endl;
}
~Resource()
{ cout << "Resource " << id << "
released" << endl; }
};
void withRawPointer()
{
Resource *r
= new Resource(1);
throw
runtime_error("failure after acquiring resource 1");
delete
r; //
never reached: memory leak
}
void withSmartPointer()
{
unique_ptr<Resource> r(new Resource(2)); // RAII: released automatically
throw
runtime_error("failure after acquiring resource 2");
}
int main()
{
try {
withRawPointer(); }
catch
(const exception &e) { cout << "Caught: " << e.what()
<< endl; }
try {
withSmartPointer(); }
catch
(const exception &e) { cout << "Caught: " << e.what()
<< endl; }
return 0;
}
Output:
Resource 1 acquired
Caught: failure after acquiring resource 1
Resource 2 acquired
Resource 2 released
Caught: failure after acquiring resource 2
Resource 1 is acquired with new
and the delete after the throw is skipped, so “Resource 1 released” never appears:
the memory is leaked. Resource 2 is owned by a unique_ptr,
whose destructor runs during stack unwinding and releases it.
|
Version Note: unique_ptr
and shared_ptr
(header <memory>) were introduced in C++11.
make_unique
was added in C++14. The older auto_ptr
was deprecated in C++11 and removed in C++17; use unique_ptr
instead. |
1.6 Levels of exception safety
|
Guarantee |
Meaning |
Example |
|
No-throw (noexcept) |
The operation never throws |
Destructors, swap of simple types, simple getters |
|
Strong |
If an exception occurs the state is exactly as before the
call (commit or rollback) |
Copy-and-swap assignment; transfer that rolls back |
|
Basic |
No leaks and all invariants hold, but the values may have
changed |
Most standard-library operations |
|
None |
Leaks or corrupted data are possible |
Code that mixes raw new with throwing calls |
Program 6.8: A money transfer with only the
basic guarantee, and one with the strong guarantee.
#include <iostream>
#include <stdexcept>
using namespace std;
class Account
{
public:
double
balance;
bool
frozen;
Account(double b, bool f = false) : balance(b), frozen(f) {}
void
withdraw(double a)
{
if (a
> balance) throw runtime_error("Insufficient balance");
balance
-= a;
}
void
deposit(double a)
{
if
(frozen) throw runtime_error("Target account is frozen");
balance
+= a;
}
};
/* Basic guarantee only: if deposit() fails, the
money has already left 'from' */
void transferBasic(Account &from, Account
&to, double amount)
{
from.withdraw(amount);
to.deposit(amount);
}
/* Strong guarantee: undo the first step if the
second one fails */
void transferStrong(Account &from, Account
&to, double amount)
{
from.withdraw(amount);
try {
to.deposit(amount);
}
catch (...)
{
from.deposit(amount);
// roll back
throw;
}
}
int main()
{
Account
a(1000), b(500, true);
try {
transferBasic(a, b, 300); }
catch
(const exception &e) {
cout
<< "Basic : " << e.what() << ", balance of a =
" << a.balance
<< endl;
}
Account
c(1000);
try {
transferStrong(c, b, 300); }
catch
(const exception &e) {
cout
<< "Strong: " << e.what() << ", balance of c =
" << c.balance
<< endl;
}
return 0;
}
Output:
Basic : Target account is frozen, balance of a = 700
Strong: Target account is frozen, balance of c = 1000
transferBasic withdraws first and
then fails to deposit: 300 has vanished from account a
(700 left). transferStrong catches the
failure of the second step, restores the first (from.deposit(amount))
and rethrows with throw;, so the
account still has 1000.
1.7 Application: file handling
By default C++ streams do not throw: failures set state flags such as failbit. Calling exceptions()
makes a stream throw ios_base::failure
instead, so file errors can be handled like any other exception.
Program 6.9: Opening a file that does not
exist.
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
ifstream
file;
// make the
stream throw
file.exceptions(ifstream::failbit | ifstream::badbit);
try {
file.open("no_such_file.txt");
string
line;
getline(file, line);
cout
<< "First line: " << line << endl;
}
catch
(const ifstream::failure &e) {
cout
<< "File error: could not open or read the file" << endl;
}
cout
<< "Program continues." << endl;
return 0;
}
Output:
File error: could not open or read the file
Program continues.
The file is not found, so open()
sets failbit and the stream throws.
The text of what() is implementation-defined
and is not printed.
2. Guidelines: When to Use
Exceptions
|
Use
exceptions for |
Do
not use exceptions for |
|
Failures that the current function cannot handle itself |
Normal, expected results (end of a loop, item not found in
a search that may fail routinely) |
|
Errors in constructors and operators, which cannot return
codes |
Control flow in ordinary logic |
|
Errors that must not be ignored |
Performance-critical inner loops where a failure is common |
|
Reporting errors from library code to unknown callers |
Errors that the caller can check cheaply beforehand, with a
simple if |
•
Throw exceptions by value and catch them by const reference.
•
Derive custom exceptions from std::exception.
•
Give resources to objects (RAII) so that clean-up is
automatic.
•
Never let an exception leave a destructor; mark
functions that cannot fail noexcept.
•
Catch only the exceptions that you can do something
about.
3. Complete Unit Revision
3.1 Templates
|
Topic |
Key
points |
|
Generic function |
template
<typename T>
before a function; one definition, many instantiations |
|
Deduction and explicit arguments |
f(5) deduces T; f<double>(5) specifies it; mixed types in f(T, T) fail |
|
Template versus overloading |
Template: one generic body; overload: separate bodies. An
exact ordinary function is preferred to a template |
|
Generic class |
Class with type parameters; objects need explicit arguments
(Box<int>) until C++17 |
|
Out-of-class members |
template
<typename T> and
ClassName<T>::; keep in the header |
|
Non-type and default parameters |
template
<typename T, int SIZE = 5>; SIZE must be a constant |
|
typename |
Type parameter declaration; marks dependent type names |
|
export |
C++98: separate definition of templates (removed in C++11);
C++20: used for modules |
|
Power of templates |
STL, specialization, compile-time computation (templates, constexpr), generic algorithms |
3.2 Exception handling
|
Topic |
Key
points |
|
Keywords |
try monitors, throw raises, catch handles |
|
Flow |
Termination model: control continues after the handlers;
the rest of the try block is skipped |
|
Handler matching |
Exact type or derived-to-base; no ordinary conversions;
first match wins; catch (...) last |
|
Propagation and unwinding |
Uncaught exceptions go to the callers; local objects are
destroyed in reverse order |
|
Derived class exceptions |
Derived handlers before base handlers; catch by const reference; avoid slicing |
|
Options |
Specific, general, catch-all, rethrow (throw;), recover, wrap (nested), terminate |
|
terminate() |
Default action abort(); change with set_terminate(); handler must not return |
|
unexpected() |
Legacy: violated specification; default calls terminate(); removed in C++17 |
|
uncaught_exception() |
Legacy: is an exception in flight? Removed in C++20; use uncaught_exceptions() |
|
exception, bad_exception |
Base of standard exceptions with what(); bad_exception replaces unexpected exceptions |
|
Application |
Validation, constructors, templates, RAII, strong
guarantee, file handling |
3.3 Comparison of terminate(),
unexpected() and uncaught_exception()
|
Function |
Purpose |
Called
when |
Default
behaviour |
Status |
|
terminate() |
Ends the program |
Handling fails (no handler, noexcept violation, …) |
Calls abort() |
Current |
|
unexpected() |
Handles a violated specification |
A function throws an unlisted exception |
Calls terminate() |
Removed in C++17 |
|
uncaught_exception() |
Detects an active exception |
Called by the program (e.g. in a destructor) |
Returns true or false |
Removed in C++20; replaced by uncaught_exceptions() |
4. Which C++ Standard Does a
Feature Need?
The table gives the status of each feature of this unit. Yes =
part of the standard, Dep. = deprecated (still valid but should be
avoided), Removed = no longer part of the standard.
|
Feature |
C++98/03 |
C++11 |
C++14 |
C++17 |
C++20 |
|
Function and class templates |
Yes |
Yes |
Yes |
Yes |
Yes |
|
export
template (separate
definition) |
Yes (rare) |
Removed |
Removed |
Removed |
Removed |
|
auto return type with trailing -> |
No |
Yes |
Yes |
Yes |
Yes |
|
auto return type deduced alone |
No |
No |
Yes |
Yes |
Yes |
|
Class template argument deduction |
No |
No |
No |
Yes |
Yes |
|
Concepts (requires) |
No |
No |
No |
No |
Yes |
|
try, throw, catch |
Yes |
Yes |
Yes |
Yes |
Yes |
|
throw(T) specification |
Yes |
Dep. |
Dep. |
Removed |
Removed |
|
throw() specification |
Yes |
Dep. |
Dep. |
Dep. |
Removed |
|
noexcept |
No |
Yes |
Yes |
Yes |
Yes |
|
unexpected(), set_unexpected() |
Yes |
Dep. |
Dep. |
Removed |
Removed |
|
uncaught_exception() |
Yes |
Yes |
Yes |
Dep. |
Removed |
|
uncaught_exceptions() |
No |
No |
No |
Yes |
Yes |
|
terminate(), set_terminate(), bad_exception |
Yes |
Yes |
Yes |
Yes |
Yes |
|
exception_ptr, nested exceptions, get_terminate() |
No |
Yes |
Yes |
Yes |
Yes |
|
unique_ptr; auto_ptr |
auto_ptr only |
unique_ptr; auto_ptr Dep. |
Yes |
auto_ptr Removed |
Yes |
|
Note: Compilers often keep
removed features as extensions, so a program may still compile in a newer
mode (with warnings). The table describes the standard. To test a
program against a specific standard with GCC or Clang use -std=c++98,
-std=c++11,
-std=c++14,
-std=c++17
or -std=c++20. |
5. Common Mistakes in This Unit
|
Mistake |
Correction |
|
Calling f(10,
2.5) for f(T, T) |
Use explicit arguments, a cast or two type parameters |
|
Defining template member functions in a .cpp file |
Put template definitions in the header |
|
Forgetting typename before a dependent type |
Write typename
Container::value_type |
|
Base-class handler before the derived-class handler |
Derived first, base next, catch (...) last |
|
catch
(exception e) by value |
Use catch (const
exception &e) |
|
throw
e; to rethrow |
Use throw; |
|
Expecting throw 5 to be caught as double |
Handler types must match exactly |
|
Throwing from a destructor |
Catch inside; destructors are noexcept |
|
Using raw new in code that may throw |
Use unique_ptr or another RAII object |
|
Using throw(T) or unexpected() in new code |
Use noexcept; these features are removed |
6. Self-Assessment Quiz
|
No. |
Question |
(a) |
(b) |
(c) |
(d) |
|
1 |
Which keyword starts a template declaration? |
generic |
template |
typename |
class |
|
2 |
In a template parameter list, class T and typename
T are: |
Different |
Equivalent |
Valid only for classes |
Valid only in C++20 |
|
3 |
For T add(T, T), the call add(10, 2.5): |
Returns 12.5 |
Returns 12 |
Fails: conflicting deduction |
Calls a specialization |
|
4 |
Before C++17 an object of a class template needs: |
No arguments |
Explicit type arguments |
A macro |
A friend function |
|
5 |
Inside a template, typename is used to: |
Declare a variable |
Mark a dependent name as a type |
Throw an exception |
Include a header |
|
6 |
export
template (C++98) was
removed in: |
C++03 |
C++11 |
C++17 |
C++23 |
|
7 |
Which keyword raises an exception? |
try |
catch |
throw |
raise |
|
8 |
catch
(...) is: |
A syntax error |
The catch-all handler |
A rethrow |
A destructor |
|
9 |
A derived-class handler must appear: |
After the base handler |
Before the base handler |
Anywhere |
Outside the try block |
|
10 |
Stack unwinding means: |
Growing the stack |
Destroying local objects while leaving functions after a
throw |
Sorting the stack |
Printing the call stack |
|
11 |
If no handler matches a thrown exception: |
It is ignored |
terminate() is called |
The program restarts |
unexpected() is called |
|
12 |
unexpected() was removed from C++ in: |
C++11 |
C++14 |
C++17 |
C++20 |
|
13 |
The modern replacement for throw()
is: |
noexcept |
nothrow |
catch |
final |
|
14 |
uncaught_exceptions() returns: |
A bool |
The number of exceptions in flight |
A string |
Nothing |
|
15 |
The base class of the standard exceptions is: |
error |
std::exception |
runtime_error |
bad_alloc |
|
16 |
vector::at() with a wrong index throws: |
bad_alloc |
out_of_range |
bad_cast |
length_error |
|
17 |
An exception leaves a noexcept function. What happens? |
It is caught by the caller |
terminate() is called |
It is ignored |
The function is retried |
|
18 |
The best way to catch a class exception is: |
By value |
By const reference |
By void * |
By static |
|
19 |
Which statement rethrows the current exception? |
throw
e; |
throw; |
rethrow; |
catch; |
|
20 |
Which technique releases resources automatically during an
exception? |
goto |
RAII |
Global variables |
Macros |
Answer key
|
Q1 |
Q2 |
Q3 |
Q4 |
Q5 |
Q6 |
Q7 |
Q8 |
Q9 |
Q10 |
|
b |
b |
c |
b |
b |
b |
c |
b |
b |
b |
|
Q11 |
Q12 |
Q13 |
Q14 |
Q15 |
Q16 |
Q17 |
Q18 |
Q19 |
Q20 |
|
b |
c |
a |
b |
b |
b |
b |
b |
b |
b |
7. Unit Question Bank
Section A: Short-answer questions
1.
What is a template? State two advantages.
2.
What is the difference between a function template and
a class template?
3.
What is the use of typename
in a template? What was export
used for?
4.
What are the three keywords used in exception handling?
5.
What happens when an exception is thrown but not
caught?
6.
What is stack unwinding?
7.
Explain catch (...).
8.
What is the use of terminate()?
What does noexcept mean?
9.
What is bad_exception?
10. What
is RAII?
Section B: Long-answer questions
1.
Explain generic functions with a program.
2.
Explain generic classes, non-type parameters and member
functions defined outside the class.
3.
Explain the exception handling mechanism with the flow
of control and a program.
4.
Explain handling of derived class exceptions and the
order of handlers.
5.
Describe the options available for handling exceptions.
6.
Explain terminate(),
unexpected() and uncaught_exception() with programs, and mention their
status in modern C++.
7.
Explain the standard exception classes with their
hierarchy.
8.
Explain how templates and exception handling can be
combined in a generic stack, with a program.
9.
Discuss exception safety and RAII with examples.
Section C: Programming questions
1.
Write a function template to find the largest of two
numbers.
2.
Write a template to swap two values.
3.
Write a class template Pair<T1,
T2>.
4.
Write a generic stack class using templates.
5.
Write a program that handles division by zero using
exception handling.
6.
Write a program with multiple catch
blocks and a catch-all.
7.
Write a program that defines a custom exception class
and uses it in a hierarchy.
8.
Write a program with a generic safe array that throws out_of_range.
9.
Write a program that shows stack unwinding with
destructors.
10. Write
a program that retries invalid input in a loop.
8. Index of Programs and How to
Compile Them
|
Programs |
Module |
Topic |
Compile
with |
|
1.1–1.5 |
1 |
Generic functions |
g++
-std=c++17 |
|
1.3 (auto return) |
1 |
Needs C++14 or later |
-std=c++14 |
|
concepts example |
1 |
Constraints |
-std=c++20 |
|
2.1–2.7 |
2 |
Class templates, typename, specialization, power of
templates |
-std=c++17 (2.3 CTAD needs C++17) |
|
module example |
2 |
C++20 modules |
-std=c++20
-fmodules-ts |
|
3.1–3.7 |
3 |
try, catch, propagation, unwinding |
-std=c++17 |
|
4.1–4.8 |
4 |
Derived exceptions, handling options |
-std=c++17 (4.7 needs C++11 or later) |
|
5.1–5.3, 5.7–5.9 |
5 |
terminate, noexcept, uncaught_exceptions, standard
exceptions |
-std=c++17 |
|
5.4–5.6 |
5 |
Legacy: unexpected, bad_exception, uncaught_exception |
-std=c++14 |
|
6.1–6.9 |
6 |
Applications |
-std=c++17 |
Use -Wall -Wextra while compiling to
see warnings. All programs were compiled and run with GCC 13, and their outputs
are shown exactly as produced. A package with the source file of every program
is provided separately.
No comments:
Post a Comment