Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

C++ Module 13

Error handling interview questions

19 interview questions on error handling from C++: short warm-ups, then what each harder question tests, the first step of a good answer and its follow-ups.

19 questions: 5 warm-ups and 14 with model answers · Levels: Fresher to senior

Warm-up questions

Short questions with short answers, each answered in full.

  1. Fresher

    Why do you throw by value and catch by const reference?

    Answered in the lesson C++ exceptions: throw, catch and stack unwinding

  2. Fresher

    What are the basic, strong and nothrow exception-safety guarantees?

    Answered in the lesson Exception safety guarantees in C++

  3. Fresher

    What does std::expected<T, E> hold, and how is it different from std::optional<T>?

    Answered in the lesson std::expected vs exceptions vs error codes

  4. Fresher

    What is the difference between assert and static_assert?

    Answered in the lesson Assertions, preconditions and [[assume]]

  5. Fresher

    What is a backtrace, and how do you get one from a C++ program that crashed?

    Answered in the lesson Debugging crashes: backtraces and std::stacktrace

Questions with model answers

What each question tests, the first step of a good answer and the follow-ups to expect.

  1. Fresher to mid

    A batch job dies with "terminate called after throwing an instance of 'std::runtime_error'" and exit status 134. Its log, written by a class that flushes buffered lines in its destructor, is missing the last lines. Explain both symptoms and what you would change.

    What it tests
    What happens when no handler matches, why no destructor ran, what exit status 134 means, and catching in main against keeping the place of the throw for diagnosis.
    First step
    The message says no handler matched, so std::terminate ran. Both GCC and Clang follow the Itanium C++ ABI, which looks for a handler before it unwinds anything; with none found, no destructor ran, so the log's buffer was never flushed. 134 is 128 plus 6: std::terminate called std::abort, which raises SIGABRT.
    Follow-ups

    From the lesson C++ exceptions: throw, catch and stack unwinding

    Model answer, Pro. Model answers open with any pass; prices are in the notice on this page.

    Opening the model answers with your pass…

    Model answers open with any MySmartCoPilot pass.

    • Pro pass · 1 week₹79$2.99
    • 30 days₹179$5.99
    • 1 year₹1,699$45

    One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

    It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 3 minutes
  2. Mid to senior

    You are designing the exceptions of a payments client library that several teams will use. Which classes do you define, what do they derive from, what data do they carry, and how should callers in different layers catch them?

    What it tests
    Designing an exception hierarchy around the decisions callers make, standard base classes, context carried in members that copy without throwing, and never making what() part of the interface.
    First step
    Start from what a caller must do differently: retry later, fix its request, or give up and report. Define one base, PaymentError, derived from std::runtime_error, and one subclass for each of those decisions, each carrying the data its handler needs, such as a retry delay or the name of the invalid field.
    Follow-ups

    From the lesson C++ exceptions: throw, catch and stack unwinding

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 3 minutes
  3. Fresher to mid

    Inventory::transfer(item, from, to, qty) subtracts qty from one warehouse's std::map<std::string, int> and adds it to another's. After a std::bad_alloc in production, some stock disappeared. Make transfer strongly exception-safe, and explain how you would test it.

    What it tests
    Finding the step that can throw, doing every allocation before any visible change, validating first, and proving the fix with fault injection.
    First step
    Find the operation that can throw. Changing an int that already exists cannot fail, but to[item] may insert a new node, which allocates. If that comes after from[item] -= qty, a failed allocation loses the stock, so do the insertion first and change both counts only afterwards.
    Follow-ups

    From the lesson Exception safety guarantees in C++

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 3 minutes
  4. Mid to senior

    A teammate wants every member function of your types to give the strong guarantee, starting with the assignment operator of a Matrix that holds a 1 GiB buffer. When is the strong guarantee too expensive, and what do you promise instead?

    What it tests
    The memory and time that copy-and-swap costs on a large object, the basic guarantee the standard library itself gives, and letting callers opt in to the strong guarantee.
    First step
    Work out the cost first. Copy-and-swap assignment of a 1 GiB matrix allocates a second gigabyte and copies all of it, even when the target already has a buffer of the right size. Then ask what callers gain: whether they would use a half-assigned matrix at all, or discard it after the exception.
    Follow-ups

    From the lesson Exception safety guarantees in C++

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 3 minutes
  5. Mid to senior

    A move-only Connection type re-registers its socket with an event loop in its move constructor, which can therefore throw. A std::vector of connections sometimes holds dead connections after a std::bad_alloc. Explain what happened and how you would fix the type.

    What it tests
    How std::vector relocates elements when it grows, why a throwing move of a type that cannot be copied leaves unspecified results, and designing moves that cannot fail.
    First step
    Start from what the vector does when it outgrows its buffer: it relocates every element into a new one. A Connection cannot be copied, so the vector has to use the move constructor, which can throw. Then work out what a relocation that fails halfway leaves in the old buffer and in the new one.
    Follow-ups

    From the lesson Exception safety guarantees in C++

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 3 minutes
  6. Mid to senior

    You are writing the parser layer of a log-processing library. Should its functions return std::expected with an enum, with std::error_code, or with a struct of context as the error, and how do callers in the other layers use what you return?

    What it tests
    Choosing an error type by what callers do with it, the cost of rich errors, converting errors between layers with transform_error, and when errors must mix with system errors.
    First step
    List what callers do with a failure: skip the line, show it to a person, count failures by kind, or report a system error from below. A small struct with an enum kind and a position serves the first three; std::error_code earns its place only where errors must mix with system errors.
    Follow-ups

    From the lesson std::expected vs exceptions vs error codes

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 3 minutes
  7. Mid to senior

    A game engine builds with -fno-exceptions, and about 400 functions report failure with a bool and an out-parameter. You propose std::expected instead. What can go wrong in such a build, and which rules and tooling do you put in place?

    What it tests
    What std::expected does without exceptions, value() that aborts, making every ignored result visible with every compiler, and migrating a large code base in safe steps.
    First step
    Start from the build mode: with -fno-exceptions, value() on an error cannot throw, so it ends the game. The rules must forbid unchecked value() and make every ignored result visible, and the change must go one subsystem at a time, with the old functions kept until their callers have moved.
    Follow-ups

    From the lesson std::expected vs exceptions vs error codes

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 3 minutes
  8. Fresher to mid

    A C library reports failure by returning -1 and leaving the reason in errno. Wrap one of its functions so that C++ callers get std::expected<T, std::error_code>, and explain which mistakes with errno your wrapper prevents.

    What it tests
    Turning errno into a std::error_code with the right category, reading errno only after a failure and at once, and keeping error state out of globals.
    First step
    Call the function and look at errno only if it returned -1, and then at once, before any other call can change it. Return std::unexpected(std::error_code(errno, std::generic_category())) in that case, and the value otherwise, without looking at errno at all.
    Follow-ups

    From the lesson std::expected vs exceptions vs error codes

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 2 minutes
  9. Fresher to mid

    A crash happens only in release builds. In the code you find assert(queue.pop(job)); and assert(init_logging());. Explain the bug, how you would find every such case in a large code base, and how you would stop new ones from appearing.

    What it tests
    What NDEBUG does to assert, side effects hidden in assertion conditions, finding them with tools, and team rules that keep assertions free of work.
    First step
    With NDEBUG defined, assert(anything) expands to ((void)0), so pop and init_logging are never called in release builds: no job is taken from the queue and logging never starts. Move each call onto its own line, keep its result, and assert on the result.
    Follow-ups

    From the lesson Assertions, preconditions and [[assume]]

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 2 minutes
  10. Mid to senior

    Your image library's public Image::pixel(x, y) receives coordinates that callers compute, some from user files. Should it assert, throw, return an error or use [[assume]]? Defend a policy, including what the library's own filters do in their inner loops.

    What it tests
    Telling public preconditions from internal invariants, what checks cost in hot loops, checking once outside a loop, and offering checked and unchecked access side by side.
    First step
    Ask who can break the condition. Coordinates derived from user files can be wrong without any bug in the library, so the public function must check them in every build. The library's own filters loop over bounds they already know, so they should not pay for a check on every pixel.
    Follow-ups

    From the lesson Assertions, preconditions and [[assume]]

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 3 minutes
  11. Mid to senior

    A pull request adds [[assume(width % 16 == 0)]] to a hot loop of an image filter and claims a 20 % speed-up. What do you check before you approve it, and what would make you reject it?

    What it tests
    What an assumption promises, the undefined behaviour of a broken one, verifying a performance claim, and pairing every assumption with a check.
    First step
    Trace where width comes from. If any caller can pass a width that is not a multiple of 16, for example from an image file, the assumption is false for those inputs and the behaviour is undefined, so the change is wrong whatever it gains.
    Follow-ups

    From the lesson Assertions, preconditions and [[assume]]

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 3 minutes
  12. Mid to senior

    A Linux service crashes with SIGSEGV about once a day, writes no log line, and nobody can reproduce it. Walk through how you would get from the next crash to the line of code that caused it.

    What it tests
    Making a crash that cannot be reproduced leave evidence: core files, debug information kept per build, a safe crash handler, sanitizer builds in staging, and reading what they produce.
    First step
    Make the next crash leave evidence. Enable core files for the service, keep the debug information of the exact build that runs in production, and add a signal handler that writes the signal and a backtrace with async-signal-safe calls before the process dies.
    Follow-ups

    From the lesson Debugging crashes: backtraces and std::stacktrace

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 3 minutes
  13. Mid to senior

    A teammate's SIGSEGV handler logs the crash with std::println and then calls std::exit(1). Sometimes the process hangs instead of exiting. Why, and how would you rewrite the handler?

    What it tests
    Async-signal safety, what allocating or locking does inside a handler, exit against _exit and re-raising the signal, and what a safe handler may do.
    First step
    Start from where the handler runs: on the crashed thread, in the middle of whatever code the signal interrupted, which may be inside malloc or an output stream. Then list what std::println and std::exit need from that code before they can finish.
    Follow-ups

    From the lesson Debugging crashes: backtraces and std::stacktrace

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 2 minutes
  14. Mid to senior

    A crash report from a release build shows main calling free() directly, but in the source main calls three of your functions before anything is freed. Explain the missing frames, and how you would get complete stacks from the next release.

    What it tests
    Inlining, tail calls and frame pointers, what debug information still records, return addresses after calls that never return, and building releases that can be diagnosed.
    First step
    The trace shows the code that ran, minus frames: the optimiser inlined the three functions into main or turned a final call into a jump, and a walk along frame pointers cannot see a function that has no frame of its own. The debug information may still describe the inlined calls.
    Follow-ups

    From the lesson Debugging crashes: backtraces and std::stacktrace

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 3 minutes

All C++ interview questions · The C++ track

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.