Exceptions and files

Intermediate

Introduction

Things go wrong in every real program, and data has to outlive it. C++ handles both with tools that fit together well: exceptions separate the error path from the normal path, and file streams work just like cin and cout.

How it works

Throwing. throw stops the current function and looks for a matching catch up the call stack. If none is found, the program ends.

Standard exceptions. <stdexcept> has types such as runtime_error, invalid_argument and out_of_range, each carrying a message that what() returns. Library functions use them too: v.at(i) throws out_of_range, and stoi throws invalid_argument.

Catching. Catch by const reference. A catch for a base type such as exception also catches all the types derived from it, so put specific handlers first.

#include <iostream>
#include <stdexcept>
using namespace std;

int divide(int a, int b) {
    if (b == 0) {
        throw invalid_argument("cannot divide by zero");
    }
    return a / b;
}

int main() {
    try {
        cout << divide(10, 2) << endl;
        cout << divide(1, 0) << endl;
        cout << "not reached" << endl;
    } catch (const invalid_argument& e) {
        cout << "error: " << e.what() << endl;
    }
    cout << "done" << endl;
    return 0;
}
Open in compiler

Files. <fstream> provides ifstream for reading and ofstream for writing. They use the same >>, << and getline as the console.

Automatic closing. A stream closes its file when the stream object goes away, even if an exception occurs. This technique is called RAII, and it is central to modern C++.

A failed open does not throw by default. Test the stream instead: if (!in).

Files in StepVioz exist in memory while the program runs. The same code writes real files when compiled on your own computer.

Syntax

try {
    risky();
} catch (const exception& e) {
    cout << e.what() << endl;
}

ifstream in("data.txt");
if (!in) { ... }

Example

#include <fstream>
#include <iostream>
#include <string>
using namespace std;

int main() {
    ofstream out("notes.txt");
    out << "first 10" << endl;
    out << "second 20" << endl;
    out.close();

    ifstream in("notes.txt");
    string word;
    int n, total = 0;
    while (in >> word >> n) {
        total += n;
    }
    cout << "total " << total << endl;

    ifstream missing("nope.txt");
    if (!missing) {
        cout << "could not open" << endl;
    }
    return 0;
}
Open in compiler

Line by line

  1. ofstream out("notes.txt") creates the file and opens it.
  2. Two lines are written with <<, just as with cout.
  3. ifstream in opens the file for reading.
  4. while (in >> word >> n) reads pairs until the file ends.
  5. Opening a missing file does not stop the program, and !missing detects it.

Expected result

total 30
could not open

In the real world

Servers catch exceptions for each request, so that one bad request cannot bring down the rest. Programs save their settings, logs and documents with file streams.

Common mistakes

  • Catching by value, which copies the exception and can lose details.
  • Not checking whether a file opened.
  • Catching a base type before a derived type, which makes the second handler unreachable.
  • Using exceptions for ordinary events, such as reaching the end of a loop.

Best practices

  • Throw standard exception types, or types derived from them.
  • Catch errors where you can do something useful about them.
  • Let streams close themselves by keeping them in a small scope.

Summary

throw reports a problem and catch handles it, with standard types such as invalid_argument carrying messages. File streams work just like cin and cout, and close themselves automatically.

Quick check

1. What happens to the rest of a try block after a throw?
2. How should an exception usually be caught?
3. What does opening a missing file with ifstream do by default?
4. What does RAII mean in practice for a file stream?

Key takeaways

  • Throw when a function cannot do its job.
  • Catch by const reference.
  • File streams close themselves when they go out of scope.

Practice problems for this lesson

My notes

Write down what you want to remember from this lesson. Notes are saved on this device as you type, and appear on your dashboard.