FREE Subscription to Dr. Dobb’s Digest: Same Great Content, New Digital Edition
Site Archive (Complete)
C++
Email
Print
Reprint

add to:
Del.icio.us
Digg
Google
Furl
Slashdot
Y! MyWeb
Blink
TABLE OF CONTENTS
August 02, 2006
Mandatory Error Codes Revisited

Forcing the use of error codes

(Page 1 of 2)
Guy Peleg
Mandatory error codes force callers of a method to accept and use the returned error code.
Guy is chief architect of event processing for the Amdocs Billing Platform (http://www.amdocs.com). He can be contacted at guy.peleg@amdocs.com.


In his article "Three Ideas" (http://www.ddj.com/dept/cpp/184401917), Andrei Alexandrescu described a framework for "mandatory error codes" that forces callers of a method to accept and use the returned error code. In this article, I refer to these codes as "forcing methods."

The idea is simple, yet powerful: A template class ErrorCode, which holds the real error code, is returned from a forcing method. When the returned ErrorCode goes out of scope, it throws an exception—unless the caller uses the error code (using the cast operator). The caller can explicitly ignore the error code by casting the ErrorCode with IgnoreError. Listing One presents the classes that make up this framework, while Example 1 shows how you can use it.

struct IgnoreError {};

template <class T> class ErrorCode { mutable bool read_; T code_; public: ErrorCode(const T& code): read_(false), code_(code) { } ErrorCode(const ErrorCode& rhs): read_(rhs.read_), code_(rhs.code_) { rhs.read_ = true; } operator T() { // disarm exception this->read_ = true; return this->code_; } operator IgnoreError() { // disarm exception this->read_ = true; return IgnoreError(); } ~ErrorCode() { if (!this->read_) { throw MandatoryErrorCodeException(....); } } };

Listing One

ErrorCode<int> FallableFunction();	// function declaration
ErrorCode<int> result = FallableFunction();	// ok
if (FallableFunction ()) {...}	// ok
FallableFunction();	// will throw
(IgnoreError) FallableFunction();	// ok

Example 1: Using the framework.

However, the problem with this framework is the exception that might be thrown at the destructor of ErrorCode. For instance, Example 2 looks perfectly normal. You don't ignore the returned error codes; you accept and use them. There's even a special recover method that can handle everything. Well, almost everything.

void AClass::someMethod() 
{
   try {
      ErrorCode<int> ec1 = this->fallableMethod_1();
      ErrorCode<int> ec2 = this->fallableMethod_2();
      if (ec1 && ec2) {
	  this->doSomething();
      }
   }
   catch (...) {
      this->recover();
   }
}

Example 2: Problem code.

Here's the problem: If this->fallableMethod_2() throws, then the ec1 destructor is activated. But since no one has yet used ec1, another exception is thrown (from activating ec1's destructor), which terminates the process (set_terminate is called but this won't help). This is a big surprise if you've followed all the rules.

1 Mandatory Error Codes Revisited | 2 The Solution Next Page
TOP 5 ARTICLES
No Top Articles.



MICROSITES
FEATURED TOPIC

ADDITIONAL TOPICS

INFO-LINK