Mandatory Error Codes

////////////////////////////////////////////////////////////////////////////////////
// MANDATORY ERROR CODES REVISITED.
// http://www.ddj.com/dept/cpp/191601612
//
// This is implementation is copied from an article I had read about forcing the use of
// error codes in C++ programs. I'm not a fan of error codes in general,
// because I think people should use exceptions instead, but the exception
// model in C++ is so hard to get right, that sometimes I have no choice but to
// use error codes. However, even error codes lose their so called convenience when
// not taken care of. Hence the use of this framework.
//
////////////////////////////////////////////////////////////////////////////////////
#pragma once
#include <string>
#include <stdexcept>

namespace return_code_usage
{
    ///////////////////////////////////////////////////////////////////////////////
    // A simple class to indicate that a return value can be ignored. Used by a
    // programmer who is sure about s/he is doing.
    ///////////////////////////////////////////////////////////////////////////////
    struct ignore_return_code{};

    ///////////////////////////////////////////////////////////////////////////////
    // Simple exception class  that is thrown when a return value is not handled
    // correctly.
    ///////////////////////////////////////////////////////////////////////////////
    class unhandled_return_code_exception
        : public std::exception
    {
    public:
        unhandled_return_code_exception()
            : err_text_("")
        {
        }
        unhandled_return_code_exception(const std::string &err_text)
            : err_text_(err_text)
        {
        }

        const char *what( ) const{
            return err_text_.c_str();
        }

        ~unhandled_return_code_exception(){/* */}
    private:
        std::string err_text_;

    };
    ///////////////////////////////////////////////////////////////////////////////
    // This is the class that wraps the return code. If its not recieved by a
    // return_code class then the exception will not be disarmed, and an exception
    // will be thrown in the destructor.
    //
    // By having a sepereate class with a exception-throwing exception, it is ensured
    // that should a function returning a throwable_return_code object, throws an exception,
    // then an exception from throwable_return_code's destructor is not thrown, when
    // the stack is unwinding.
    ///////////////////////////////////////////////////////////////////////////////
    template <class CODE>
    class throwable_return_code
    {
        template<class CODE> friend class return_code;
    public:
        // constructor recieve the code and arm the exception
        throwable_return_code(CODE r_code)
            : code_(r_code)
            , throw_(true)
        {
        }
        //explicitly ignore error codes and avoid exception
        operator ignore_return_code(){
            throw_ = false;
            return ignore_return_code();
        }

        ~throwable_return_code(){
            //will throw unless something is done to prevent it.
            if (throw_){
                throw unhandled_return_code_exception();
            }
        }
    private:
        CODE code_;
        bool throw_;
    };

    ///////////////////////////////////////////////////////////////////////////////
    // Simple class that recieved the throwable_return_code, and disarms the
    // throwable_return_code exception-throwing destructor. This class is only used
    // by a developer who knows what s/he is doing when disarming the exception.
    ///////////////////////////////////////////////////////////////////////////////

    template<typename CODE_T>
    class return_code
    {
        typedef CODE_T code_type;
    public:
        // Explicit ctor to make sure that hte user of this class
        // knows what s/he is doing
        explicit return_code(throwable_return_code<code_type> &code)
            : code_(code.code_)
        {
            code.throw_ = false;
        }
        ~return_code(){ }
        operator code_type (){
            return code_;
        }
    private:
        code_type code_;
    };
}

Here is test implementation.

#include <iostream>
#include "return_code_usage.hpp"

using namespace std;
using namespace return_code_usage;

void print_function_name(std::string function_name)
{
    std::cout
        << std::string(function_name.size(), '-')<<std::endl
        << function_name                         <<std::endl
        << std::string(function_name.size(), '-')<<std::endl;
}

#define PRINT_FUNCTION_NAME print_function_name(__FUNCTION__)


throwable_return_code<int> fallible_function(){
    PRINT_FUNCTION_NAME;
    return 1;
}

struct point_class{
    int x,y;
    point_class(int x_, int y_)
        : x(x_), y(y_){}
};

// For custom types, need to have overloaded operators for comparison
// not needed for basic types.
bool operator == (const point_class &a, const point_class &b){
    return (a.x == b.x) && (a.y==b.y);
}

throwable_return_code<point_class> another_fallible_function(){
    PRINT_FUNCTION_NAME;
    point_class p(1,2);
    return p;
}

int main(int argc, char *argv[]){
    // Okay
    return_code<int> result1(fallible_function());
    //This doesn'nt work with an explicit constructor
    return_code<int> result2 = (return_code<int>)fallible_function();

    // OK
    if((return_code<int>(fallible_function()) == 0)){

    }

    // OK
    if (0==(return_code<int>)fallible_function()){
    }

    //OK because explicitly ignoring error
    (ignore_return_code)fallible_function();

    //OK
    return_code<point_class> result3 = (return_code<point_class>)another_fallible_function();

    //OK - with thedefinition of overloaded equality operator
    if (return_code<point_class>(another_fallible_function())==point_class(1,2)){
    }

    // OK with overloaded equality operator.
    if (point_class(1,2) == (return_code<point_class>)another_fallible_function()){
    }

    // will throw an exception
    fallible_function();
    return 0;
}


		
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: