AI InterviewSearch…Search problems, topics, or pages…Ctrl KGet started
Skip to content

15 Errors and exceptions / Checkpoint

Checkpoint — Errors and exceptions

25 min · +25 XP · 3 exercises · 14 questions

Exercises0/3
Quiz · 70% to clear14 q

This checkpoint covers the whole module: throwing and catching with the standard hierarchy and your own, the three exception-safety guarantees with RAII and noexcept, std::optional for a value that may be absent, std::variant with std::visit for a value that is one of several types, and error codes, assertions and the per-layer strategy.

How it works. Fourteen questions and three programs. You need 70% on the questions and every program accepted to clear the module. You can retake it as often as you like; your best score counts.

Before you start, make sure you can answer these from memory:

  • Why is catch (const std::exception& e) right and catch (std::exception e) wrong?
  • What does v.at(9) throw, and what does v[9] do instead?
  • What does std::vector do on reallocation when the element's move constructor is not noexcept?
  • Is *opt on an empty optional a throw or undefined behaviour?
  • What does std::visit refuse to compile?
  • What does NDEBUG do to an assert?
  • In a parse → validate → execute pipeline, which layer throws?

The three programs are a score reader that translates std::stoi's exceptions into its own hierarchy, an RPN evaluator that returns a std::variant of result or failure, and a key–value store whose transactions roll back through an RAII guard. Every program must catch what it provokes and return 0 — an exception that escapes main is a runtime error, not a wrong answer.

Common questions

What does v.at(9) throw, and what does v[9] do instead?

On a vector with fewer than ten elements, v.at(9) throws std::out_of_range. v[9] performs no check at all, so reading past the end is undefined behaviour rather than an exception.

Is *opt on an empty optional a throw or undefined behaviour?

Undefined behaviour. The dereference operators of std::optional do not check; only value() throws, with std::bad_optional_access. Test the optional with if (opt) before dereferencing it.

What does NDEBUG do to an assert?

When NDEBUG is defined, assert expands to nothing, so its condition is not even evaluated. That is why an assertion must have no side effects and must never be the only check on user input.

In a parse, validate, execute pipeline, which layer throws?

The execute layer. Parse returns an optional because malformed input is ordinary, validate returns an error code the caller switches on, and execute throws when the world refuses; the reporting boundary then catches, translates and prints.

C++ Error Handling Quiz: Exceptions, Optional and Variant

Practise C++ error handling with 14 questions and three programs: translating stoi exceptions, an RPN evaluator returning a variant, and an RAII rollback guard.

  • Course: C++ study plan
  • Module: Errors and exceptions
  • Kind: Checkpoint — cleared at 70%
  • Reading time: 25 min
  • Runtime: Clang 18 · C++20

Checkpoint — Errors and exceptions is the checkpoint that closes the Errors and exceptions module: a graded quiz and whole-program exercises, passed at 70%.

Instructions

This checkpoint covers the whole module: throwing and catching with the standard hierarchy and your own, the three exception-safety guarantees with RAII and noexcept, std::optional for a value that may be absent, std::variant with std::visit for a value that is one of several types, and error codes, assertions and the per-layer strategy.

How it works. Fourteen questions and three programs. You need 70% on the questions and every program accepted to clear the module. You can retake it as often as you like; your best score counts.

Before you start, make sure you can answer these from memory:

  • Why is catch (const std::exception& e) right and catch (std::exception e) wrong?
  • What does v.at(9) throw, and what does v[9] do instead?
  • What does std::vector do on reallocation when the element's move constructor is not noexcept?
  • Is *opt on an empty optional a throw or undefined behaviour?
  • What does std::visit refuse to compile?
  • What does NDEBUG do to an assert?
  • In a parse → validate → execute pipeline, which layer throws?

The three programs are a score reader that translates std::stoi's exceptions into its own hierarchy, an RPN evaluator that returns a std::variant of result or failure, and a key–value store whose transactions roll back through an RAII guard. Every program must catch what it provokes and return 0 — an exception that escapes main is a runtime error, not a wrong answer.

Common questions

What does v.at(9) throw, and what does v[9] do instead?

On a vector with fewer than ten elements, v.at(9) throws std::out_of_range. v[9] performs no check at all, so reading past the end is undefined behaviour rather than an exception.

Is *opt on an empty optional a throw or undefined behaviour?

Undefined behaviour. The dereference operators of std::optional do not check; only value() throws, with std::bad_optional_access. Test the optional with if (opt) before dereferencing it.

What does NDEBUG do to an assert?

When NDEBUG is defined, assert expands to nothing, so its condition is not even evaluated. That is why an assertion must have no side effects and must never be the only check on user input.

In a parse, validate, execute pipeline, which layer throws?

The execute layer. Parse returns an optional because malformed input is ordinary, validate returns an error code the caller switches on, and execute throws when the world refuses; the reporting boundary then catches, translates and prints.

Exercises

Score reader

Read scores from text and translate the standard library's exceptions into your own hierarchy at the boundary. ScoreError derives from std::runtime_error and inherits its constructor; NotANumber and RangeError derive from ScoreError, each with a constructor taking the offending text and building the message not a number: <text> or out of range: <text>. int parseScore(const std::string& text) calls std::stoi(text, &consumed): catch its std::invalid_argument and throw NotANumber, catch its std::out_of_range and throw RangeError; a token only partly consumed is also NotANumber, and a score outside 0–100 is also RangeError. The library's what() is never printed — only yours.

main reads n records and, per record, one try with a handler per derived type that prints <name>: <what()> and counts it. At the end print the average of the accepted scores to two decimals (or none) and the rejection counts.

Input: n, then n lines <name> <score-text>. Output: n lines, then average: <x.xx> or average: none, then rejected: <a> not a number, <b> out of range.

4
ada 93
bob 9x
cy 250
dee 100

prints

ada: 93
bob: not a number: 9x
cy: out of range: 250
dee: 100
average: 96.50
rejected: 1 not a number, 1 out of range

RPN evaluator with a variant result

Evaluate reverse-Polish expressions and return the outcome as a value: struct EvalError { std::string message; }; and using Result = std::variant<long long, EvalError>;. Result evaluate(const std::string& line) splits the line into tokens; an integer (an optional - then digits, parsed with std::from_chars into an std::optional<long long>) is pushed, and + - * / pop two operands and push the result. The first failure ends the evaluation with an EvalError: bad token <tok> for anything else, stack underflow when an operator finds fewer than two operands, division by zero, empty expression when the line has no tokens, and leftover operands when more than one value remains at the end. evaluate never throws. main prints each result with std::visit and an overloaded visitor.

Input: one expression per line until EOF. Output: = <value> or error: <message> per line.

3 4 + 2 *
1 0 /
5 +
2 3
7
hello

prints

= 14
error: division by zero
error: stack underflow
error: leftover operands
= 7
error: bad token hello

Transactions that roll back

A key–value store (std::map<std::string, long long>) processes transaction blocks, each from a begin line to a commit or abort line. Commands inside a block: set <key> <value>, add <key> <value> (the key must exist), del <key> (the key must exist), get <key> (prints <key>: <value> or <key>: (none) through an std::optional lookup). A missing key throws StoreError("no key <key>") (derived from std::runtime_error).

Write Rollback, an RAII guard that copies the store in its constructor and, in its destructor, restores the copy unless commit() was called. Run each block's commands with one Rollback in scope; call commit() only when the block ended with commit. You write no rollback code at any call site: an abort, a thrown StoreError, and a block cut off by the end of input all restore the store because the guard's destructor runs. After each block main prints committed, aborted or failed: <what()>, then the store as store: k1=v1 k2=v2 … in key order, or store: (empty).

Input: blocks as described, until EOF. Output: the get lines as they happen; after each block its verdict and the store.

begin
set a 1
set b 2
commit
begin
set c 3
del zz
commit
begin
add a 10
get a
abort
begin
add b 5
get b
get q
commit

prints

committed
store: a=1 b=2
failed: no key zz
store: a=1 b=2
a: 11
aborted
store: a=1 b=2
b: 7
q: (none)
committed
store: a=1 b=7

In this module: Errors and exceptions

← Error codes, assertions and an error-handling strategy · The standards — what each C++ added, and what runs here →