🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: net.lang.c++
Article #25

Exception handling in C++

#25
From: keith gorlen
Date: Tue, 25 Feb 1986 14:28
347 lines
10466 bytes
C++ is a terrific language, but I was a bit disappointed initially that
it included no facilities for exception handling -- but wait -- maybe
"you can program that yourself"!

My favorite exception handling mechanism is the SIGNAL-ENABLE construct
of BLISS-11.  Its reasonably efficient and flexible, and it seems to
have inspired Ada's RAISE-EXCEPTION construct.

A similar facility for C++ works as follows:

	BEGINX		// start of exception block

	statements that might cause an exception to be raised

	EXCEPTION

	exception handlers; format same as body of switch statement

	ENDX		// end of exception block

As a trivial example:

	#include <stream.h>
	#include "exception.h"
	const int exception1 = 1;
	void f() { RAISE(exception1); }
	main()
	{
		BEGINX
			f();
			cerr << "This will never happen!\n";
		EXCEPTION
			case exception1: cerr << "exception1 handled\n";
		ENDX
		cerr << "End of program\n";
	}

will output:

	exception1 handled
	End of program

Of course, if no exception is raised in the first part of the block, the
handlers following the EXCEPTION keyword are not executed.  When an
exception is raised, the case with the same exception code (if any) is
executed.  Unless the flow of control is altered by a return, break,
continue, etc., execution continues with the first statement after the
ENDX whether or not an exception occurred, and whether or not a matching
case was found.

BEGINX...ENDX blocks may be nested within either part of a BEGINX...ENDX
block; i.e., the exception handlers may contain exception blocks.  An
exception is raised by executing the statement RAISE(code), causing
control to pass to the most recently executed exception block.  An
exception handler may reference the current exception code by the name
EXCEPTION_CODE.  If no case matches the current exception code, it can
be propagated up to the next most recently executed exception block by
including the statement:

	default:RAISE(EXCEPTION_CODE);

in the exception block.

The shar file attached to the end of this article contains my
implementation of this and a test program.  I would like to hear
people's comments on the following points:

1.  Will this implementation work in general, or have I forgotten
something?  Are there some dire consequences of using setjmp/longjmp in
this fashion?  Note that destructors will not be called when a block is
exited by doing a RAISE.

2.  In Ada, if an EXCEPTION block has no handler for the raised
exception, the exception is automatically propagated up to the next
level.  In my implementation, control goes to the statement after the
ENDX.  I think Ada's way is better.  Can anyone think of a way to do
this while retaining the capability of having a default error handling
case?  The problem is that there can only be one default label in a
switch statement.

2.  In Ada, the EXCEPTION block is within the scope of variables declared
in the BEGIN...EXCEPTION part.  This seems like a good idea, because the
exception handlers may want to examine these variables to decide how to handle
the exception.  It doesn't seem possible to do this directly in C++, and
it is easy to achieve the same effect simply by writing, for example:

	{
		int x;
		BEGINX
			// do something to x
			// do something that might raise an error
		EXCEPTION
			case <something>:	// use x
		ENDX
	}

But this raises the question of what happens if x is allocated to a
register.  And is there a way to force stack allocation of an auto
variable in C++?

---
	Keith Gorlen
	Computer Systems Laboratory
	Division of Computer Research and Technology
	National Institutes of Health
	Bethesda, MD 20892
	phone:	(301) 496-5363
	uucp:	{decvax!}seismo!elsie!cecil!keith

#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	exception.h
#	exception.c
#	xtest.c
# This archive created: Tue Feb 25 09:14:38 1986
export PATH; PATH=/bin:$PATH
echo shar: extracting "'exception.h'" '(1810 characters)'
if test -f 'exception.h'
then
	echo shar: will not over-write existing file "'exception.h'"
else
sed 's/^	X//' << \SHAR_EOF > 'exception.h'
	X/* exception.h -- Ada -like exception handler
	X
	XAuthor:
	X	K. E. Gorlen
	X	Bg. 12A, Rm. 2017
	X	Computer Systems Laboratory
	X	Division of Computer Research and Technology
	X	National Institutes of Health
	X	Bethesda, Maryland 20892
	X	Phone: (301) 496-5363
	X	uucp: {decvax!}seismo!elsie!cecil!keith
	X	February, 1986
	X
	XFunction:
	X	
	XDeclarations for Ada -like exception handling.
	X
	XModification History:
	X	
	X*/
	X
	X#ifndef EXCEPTIONH
	X#define EXCEPTIONH
	X
	X#include <setjmp.h>
	X
	Xclass ExceptionEnv;
	Xextern ExceptionEnv* exception_env_stack_top;
	X
	Xclass ExceptionEnv {
	X	ExceptionEnv* prev;
	X	int exceptionCode;
	X	jmp_buf env;
	Xpublic:
	X	ExceptionEnv() {	// MUST be inline
	X		prev = exception_env_stack_top;
	X		exception_env_stack_top = this;
	X		exceptionCode = setjmp(env);
	X	}
	X	~ExceptionEnv() { if (exception_env_stack_top == this) pop(); }
	X	int code()	{ return exceptionCode; }
	X	void pop()	{ exception_env_stack_top = prev; }
	X	void raise(int exception);
	X};
	X
	X#define	EXCEPTION_CODE	exception_environment.code()
	X
	X#define BEGINX {							\
	X	ExceptionEnv exception_environment;				\
	X	if (EXCEPTION_CODE == 0) {					\
	X		
	X// Statements in the scope of this exception handler block go here.
	X
	X#define EXCEPTION							\
	X	}								\
	X	else switch(EXCEPTION_CODE) {					\
	X
	X/*
	XException handlers go here; the syntax is that of a switch statement
	Xbody.  The exception code that caused this EXCEPTION block to be entered
	Xmay be accessed via the macro EXCEPTION_CODE.  The statement
	X"default:RAISE(EXCEPTION_CODE);" will propagate the current exception up
	Xto the next exception handler block if the exception is not handled by
	Xthis block; otherwise, execution continues with the first statement
	Xafter this exception block.
	X*/
	X
	X#define ENDX								\
	X	};								\
	X}									\
	X
	Xinline void RAISE(int exception)
	X{
	X	exception_env_stack_top->raise(exception);
	X}
	X
	X#endif
SHAR_EOF
if test 1810 -ne "`wc -c < 'exception.h'`"
then
	echo shar: error transmitting "'exception.h'" '(should have been 1810 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'exception.c'" '(838 characters)'
if test -f 'exception.c'
then
	echo shar: will not over-write existing file "'exception.c'"
else
sed 's/^	X//' << \SHAR_EOF > 'exception.c'
	X/* exception.c -- Ada -like exception handler library routines
	X
	XAuthor:
	X	K. E. Gorlen
	X	Bg. 12A, Rm. 2017
	X	Computer Systems Laboratory
	X	Division of Computer Research and Technology
	X	National Institutes of Health
	X	Bethesda, Maryland 20892
	X	Phone: (301) 496-5363
	X	uucp: {decvax!}seismo!elsie!cecil!keith
	X	February, 1986
	X
	XFunction:
	X
	XRun-time support for Ada -like exception handling.
	X	
	XModification History:
	X	
	X*/
	X#include <stream.h>
	X#include <osfcn.h>
	X#include <libc.h>
	X#include "exception.h"
	X
	XExceptionEnv* exception_env_stack_top;
	XExceptionEnv lastResort;
	X
	Xvoid ExceptionEnv::raise(int exception)
	X{
	X	if (exception == 0) {
	X		cerr << "Tried to RAISE exception code 0\n";
	X		abort();
	X	}
	X	if (prev == 0) {	// i.e.,  this == &lastResort
	X		cerr << "Unhandled exception code " << exception << "\n";
	X		exit(1);
	X	}
	X	pop();
	X	longjmp(env,exception);
	X}
SHAR_EOF
if test 838 -ne "`wc -c < 'exception.c'`"
then
	echo shar: error transmitting "'exception.c'" '(should have been 838 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'xtest.c'" '(1298 characters)'
if test -f 'xtest.c'
then
	echo shar: will not over-write existing file "'xtest.c'"
else
sed 's/^	X//' << \SHAR_EOF > 'xtest.c'
	X#include "exception.h"
	X#include <stream.h>
	X
	Xenum exceptionCode { EXCEPTION1=1, EXCEPTION2, EXCEPTION3, EXCEPTION4 };
	X
	Xvoid x(exceptionCode n)
	X{
	X	BEGINX
	X		if (n>EXCEPTION2) {
	X			cerr << "Raising EXCEPTION" << n << "...";
	X			RAISE(n);
	X		}
	X		cerr << "Trying normal return from function\n";
	X		return;
	X	EXCEPTION
	X		case EXCEPTION3: cerr << "EXCEPTION3 handled\n"; return;
	X		default: cerr << "trying RAISE(EXCEPTION_CODE)...";
	X			RAISE(EXCEPTION_CODE);
	X	ENDX
	X}
	X
	Xmain()
	X{
	X	cerr << "Begin exception handler test\n";
	X
	X	BEGINX
	X		cerr << "Testing normal execution\n";
	X	EXCEPTION
	X		default: cerr << "This should not happen!\n";
	X	ENDX
	X
	X	BEGINX
	X		cerr << "Raising EXCEPTION1...";
	X		RAISE(EXCEPTION1);
	X		cerr << "EXCEPTION1 not handled!\n";
	X	EXCEPTION
	X		case EXCEPTION1: cerr << "EXCEPTION1 handled\n";
	X	ENDX
	X	
	X	BEGINX
	X		cerr << "Testing nested exception block\n";
	X		x(EXCEPTION2);
	X		BEGINX
	X			cerr << "Raising EXCEPTION2...";
	X			RAISE(EXCEPTION2);
	X			cerr << "EXCEPTION2 not handled!\n";
	X		EXCEPTION
	X			case EXCEPTION2: cerr << "EXCEPTION2 handled\n";
	X				cerr << "Raising EXCEPTION3...";
	X				x(EXCEPTION3);
	X		ENDX
	X		
	X		cerr << "Raising EXCEPTION4...";
	X		x(EXCEPTION4);
	X		cerr << "EXCEPTION4 not handled!\n";
	X
	X	EXCEPTION
	X		default: cerr << "Test unhandled exception handler\n";
	X			RAISE(EXCEPTION_CODE);
	X	ENDX
	X}
SHAR_EOF
if test 1298 -ne "`wc -c < 'xtest.c'`"
then
	echo shar: error transmitting "'xtest.c'" '(should have been 1298 characters)'
fi
fi # end of overwriting check
#	End of shell archive
exit 0

-- 
---
	Keith Gorlen
	Computer Systems Laboratory
	Division of Computer Research and Technology
	National Institutes of Health
	Bethesda, MD 20892
	phone:	(301) 496-5363
	uucp:	{decvax!}seismo!elsie!cecil!keith
Technical Details
Message-ID: <51@cecil.UUCP>
Path: arc1-ca.pugleaf.net!utzoo!watmath!clyde!burl!ulysses!allegra!mit-eddie!think!harvard!seismo!elsie!cecil!keith

Show Full Headers
Complete Article Headers
Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP
Path: arc1-ca.pugleaf.net!utzoo!watmath!clyde!burl!ulysses!allegra!mit-eddie!think!harvard!seismo!elsie!cecil!keith
From: keith@cecil.UUCP (keith gorlen)
Newsgroups: net.lang.c++
Subject: Exception handling in C++
Message-ID: <51@cecil.UUCP>
Date: Tue, 25-Feb-86 09:28:13 EST
Article-I.D.: cecil.51
Posted: Tue Feb 25 09:28:13 1986
Date-Received: Fri, 28-Feb-86 07:47:09 EST
Organization: NIH-CSL, Bethesda, MD
Lines: 347