Programming Language & Its Applications β Generic Programming and Exception Handling, NEC licence examination syllabus (Nepal Engineering Council).
Throwing objects that carry data β so the handler can do more than print a message.
#include <iostream>
#include <stdexcept>
#include <string>
#include <sstream>
#include <vector>
/* Approach 1: derive from runtime_error, which stores the
message for you, and ADD structured data. */
class HttpError : public std::runtime_error {
int status;
std::string url;
public:
HttpError(int code, std::string u)
: std::runtime_error("HTTP " + std::to_string(code)
+ " for " + u),
status(code), url(std::move(u)) {}
int code() const noexcept { return status; }
const std::string& target() const noexcept { return url; }
/* the data enables DECISIONS, not just messages */
bool retryable() const noexcept {
return status == 429 || (status >= 500 && status < 600);
}
};
/* Approach 2: derive from std::exception and manage the
message yourself by overriding what(). */
class ValidationError : public std::exception {
std::string field, message;
double value, lo, hi;
public:
ValidationError(std::string f, double v, double a, double b)
: field(std::move(f)), value(v), lo(a), hi(b) {
std::ostringstream os;
os << "field '" << field << "' = " << value
<< " outside [" << lo << ", " << hi << "]";
message = os.str();
}
/* what() must be noexcept and must NOT allocate β
that is why the string is built in the constructor */
const char* what() const noexcept override {
return message.c_str();
}
const std::string& fieldName() const noexcept { return field; }
double got() const noexcept { return value; }
double min() const noexcept { return lo; }
double max() const noexcept { return hi; }
};
void fetch(const std::string &url, int simulate) {
if (simulate != 200) throw HttpError(simulate, url);
std::cout << " 200 OK " << url << "\n";
}
void validateAge(double a) {
if (a < 0 || a > 120) throw ValidationError("age", a, 0, 120);
std::cout << " age " << a << " accepted\n";
}
int main() {
/* the handler uses code() to decide POLICY */
for (int status : {200, 404, 503, 429}) {
std::cout << " fetch with status " << status << ":\n";
try { fetch("/api/students", status); }
catch (const HttpError &e) {
std::cout << " " << e.what() << "\n";
std::cout << " -> "
<< (e.retryable() ? "RETRY later"
: "give up, permanent")
<< " (code " << e.code() << ")\n";
}
}
/* the handler uses the field name and bounds */
for (double a : {22.0, -5.0, 200.0}) {
std::cout << " validateAge(" << a << "):\n";
try { validateAge(a); }
catch (const ValidationError &e) {
std::cout << " " << e.what() << "\n";
std::cout << " -> highlight input '"
<< e.fieldName() << "', suggest "
<< e.min() << ".." << e.max() << "\n";
}
}
return 0;
}
Output:
fetch with status 200:
200 OK /api/students
fetch with status 404:
HTTP 404 for /api/students
-> give up, permanent (code 404)
fetch with status 503:
HTTP 503 for /api/students
-> RETRY later (code 503)
fetch with status 429:
HTTP 429 for /api/students
-> RETRY later (code 429)
validateAge(22):
age 22 accepted
validateAge(-5):
field 'age' = -5 outside [0, 120]
-> highlight input 'age', suggest 0..120
validateAge(200):
field 'age' = 200 outside [0, 120]
-> highlight input 'age', suggest 0..120
what() is noexcept and returns const char*, not std::string. Both constraints exist because what() is called while the program is already in a failure state β allocating memory or throwing at that moment could turn a recoverable error into a hard termination.
#include <iostream>
#include <stdexcept>
#include <string>
#include <vector>
#include <sstream>
/* ---- a base for everything this subsystem throws ---- */
class BankError : public std::runtime_error {
std::string accountId;
public:
BankError(const std::string &msg, std::string acc)
: std::runtime_error(msg), accountId(std::move(acc)) {}
const std::string& account() const noexcept { return accountId; }
};
/* ---- specific failures, each with its own data ---- */
class InsufficientFunds : public BankError {
double balance, requested;
public:
InsufficientFunds(const std::string &acc, double bal, double req)
: BankError(build(acc, bal, req), acc),
balance(bal), requested(req) {}
double available() const noexcept { return balance; }
double needed() const noexcept { return requested; }
double shortfall() const noexcept { return requested - balance; }
private:
static std::string build(const std::string &a, double b, double r) {
std::ostringstream os;
os << "account " << a << ": balance Rs " << b
<< " cannot cover Rs " << r;
return os.str();
}
};
class AccountFrozen : public BankError {
std::string reason;
public:
AccountFrozen(const std::string &acc, std::string why)
: BankError("account " + acc + " is frozen: " + why, acc),
reason(std::move(why)) {}
const std::string& why() const noexcept { return reason; }
};
class DailyLimitExceeded : public BankError {
double limit, attempted, alreadyUsed;
public:
DailyLimitExceeded(const std::string &acc, double lim,
double att, double used)
: BankError("daily limit exceeded on " + acc, acc),
limit(lim), attempted(att), alreadyUsed(used) {}
double remaining() const noexcept { return limit - alreadyUsed; }
double attemptedAmount() const noexcept { return attempted; }
};
/* ---- the operation ---- */
struct Account {
std::string id;
double balance;
bool frozen;
std::string freezeReason;
double withdrawnToday;
};
const double DAILY_LIMIT = 25000.0;
void withdraw(Account &a, double amount) {
if (a.frozen)
throw AccountFrozen(a.id, a.freezeReason);
if (amount > a.balance)
throw InsufficientFunds(a.id, a.balance, amount);
if (a.withdrawnToday + amount > DAILY_LIMIT)
throw DailyLimitExceeded(a.id, DAILY_LIMIT, amount,
a.withdrawnToday);
a.balance -= amount;
a.withdrawnToday += amount;
std::cout << " OK: Rs " << amount
<< " withdrawn, balance Rs " << a.balance << "\n";
}
int main() {
Account a1{"AC-1001", 50000, false, "", 0};
Account a2{"AC-1002", 3000, false, "", 0};
Account a3{"AC-1003", 90000, true, "KYC pending", 0};
Account a4{"AC-1004", 80000, false, "", 20000};
struct Req { Account *acc; double amt; };
std::vector<Req> reqs = {
{&a1, 15000}, {&a2, 5000}, {&a3, 1000}, {&a4, 10000}
};
for (auto &r : reqs) {
std::cout << " withdraw Rs " << r.amt << " from "
<< r.acc->id << ":\n";
try { withdraw(*r.acc, r.amt); }
catch (const InsufficientFunds &e) {
std::cout << " " << e.what() << "\n"
<< " -> short by Rs " << e.shortfall()
<< ", offer overdraft\n";
}
catch (const AccountFrozen &e) {
std::cout << " " << e.what() << "\n"
<< " -> route to compliance ("
<< e.why() << ")\n";
}
catch (const DailyLimitExceeded &e) {
std::cout << " " << e.what() << "\n"
<< " -> Rs " << e.remaining()
<< " left today; suggest splitting\n";
}
catch (const BankError &e) {
std::cout << " unclassified on account "
<< e.account() << ": " << e.what() << "\n";
}
}
return 0;
}
Output:
withdraw Rs 15000 from AC-1001:
OK: Rs 15000 withdrawn, balance Rs 35000
withdraw Rs 5000 from AC-1002:
account AC-1002: balance Rs 3000 cannot cover Rs 5000
-> short by Rs 2000, offer overdraft
withdraw Rs 1000 from AC-1003:
account AC-1003 is frozen: KYC pending
-> route to compliance (KYC pending)
withdraw Rs 10000 from AC-1004:
daily limit exceeded on AC-1004
-> Rs 5000 left today; suggest splitting
std::system_error carries a std::error_code β a portable integer plus a category β so <filesystem> and networking code can report OS errors that you compare against named constants rather than parsing text. It also underpins std::error_condition for grouping equivalent errors across platforms. Search "std::error_code vs exceptions"; the design lets one API report failures either way, which is why <filesystem> functions come in throwing and non-throwing overloads.new MyError() leaks. Write a custom exception class deriving from std::exception (or runtime_error) with an overridden what() and accessors for its data β that is the standard question. Know that what() must be noexcept and returns const char*, so build the message in the constructor. The strongest answer explains why structured data beats a message: it lets the handler make decisions.Create a free account to tick topics off, take notes as you read, watch the video lessons and get a day-by-day study plan built around your exam date.
Loadingβ¦