Yesterday, I demonstrated how abusing the exception facilities of Java could allow us to conveniently encode tagged union types.

Here is a C++11 program demonstrating another use of exceptions for quickly breaking out of nested closure calls. Notice how C++11 closures help keeping the code concise, local and clear at the same time.

	enum state { CORRECT = 0, INCORRECT, INCOMPLETE };

	/** Finds the current state of a sudoku game */
	state sudoku_state(short grid[9][9])
	{
		/* This program initializes a buffer for each digit from 1 to 9.
		 * It then proceeds to test, for each row, each line and each sub-grid,
		 * that numbers are not repeated, using `buffer` as a bitset.
		 * In order to avoid resetting `buffer` before each check, we make use of
		 * the fact that between successful checks, all the numbers in `buffer`
		 * are equal to a given n. We keep this n in variable `curr`.
		 * It is then sufficient to test differences with n to spot a problem in
		 * the currently analysed subspace.
		 * The algorithm short-circuits the call stack on invalid state by
		 * throwing the state and catching it at call-site.
		 */
		int buffer[9] = {0}; // nbs from 1 to 9
		int curr = 0;
		auto test = [&](int d) {
			if (d <= 0 || d > 9) throw INCOMPLETE;
			if (buffer[d-1]++ != curr) throw INCORRECT;
		};
		auto rows_or_lines = [&](bool lines /* or rows */) {
			for (int i = 0; i < 9; ++i) {
				for (int j = 0; j < 9; ++j)
					if (lines) test(grid[i][j]);
					else test(grid[j][i]);
				++curr;
			}
		};
		auto subgrids = [&](int x, int y) {
			for (int i = x; i < x+3; ++i)
				for (int j = y; j < y+3; ++j)
					test(grid[j][i]);
			++curr;
		};
		try {
			rows_or_lines(true); rows_or_lines(false);
			for (int i = 0; i < 3; i++) for (int j = 0; j < 3; j++)
				subgrids(i*3,j*3);
		}
		catch (state err_state) { return err_state; }
		return CORRECT;
	}

Safety

C had a setjmp/longjmp capability for unwinding the stack without returning from functions properly, but it was unsafe and error-prone (not to mention the fact that C does not have RAII). In C++, this mechanism has been replaced with exceptions, but just like longjmp was not only used for simulating exceptions, we can also use exceptions for other things than reporting failures.

The fact that C++ has RAII semantics means that it is generally safe to brutally unwind the stack with an exception, as long as the objects in scope are implemented properly and you’re not manipulating pointers directly but using modern C++ idioms instead.1

Performance

I have not tested it yet, but since zero-cost-exceptions (supposedly) do not incur any overhead on the normal paths, and since in every execution of this function at most one exception is ever raised, I expect that it would not incur a very significant cost compared to a function-return-based approach… but it depends heavily on whether the compiler is able to inline the functions, and we all know speculations on performance are more often wrong than not! [hypothesis to test]

  1. Note that exception safety becomes a very tricky matter in the context of generic code, like STL collections; but when exceptions are not thrown in the middle of foreign code due to dependency injection through template metaprogramming – such as when designing an STL collection, the situation is much less hazardous and difficult to deal with.