Introduction

This simple article, primarily intended for beginners, explains the concept of using switches for state maintenance in functions.

The term 'switch', within the context of this article, refers to a simple object whose primary function is to set and unset attributes that describe the state of an execution scope.

Background

Let's take a look at some sample code:

class my_class
{
   public:

   void function_a()
   {
      run = true;

      if( condition1 ... )
      {
          run=false;
          return;
      }

      if( condition2... )
      {
          run=false;
          return;
      }

      switch( condition 3 )
      {
         case a:
         break;

         case b:
         break;

         default:
         run=false;
         return;
      }

      run = false;
   }

   bool is_running() const
   {
      return run;
   }

   protected:

   bool run;
}

Notice the object above. The object uses a boolean variable 'run' to indicate the state of 'function_a'. The nature of the function is such that it has too many exit points which implies the state variable needs to be reset before hitting each one of these exit points. To minimize the trouble, you can either re-organize the function to have a single exit point, in which case you'd still have to reset the state variable at the end or you can use a switch to accomplish the same task.

The following sample code shows a simple boolean switch. Our actual code will make use of std::bitset (see usage section).

class boolean_switch
{
    boolean_switch(){}

    bool* mpval;

    public:

    boolean_switch( bool* pval, bool initial_state )
    {
         if(pval)
         {
           mpval = pval;
           *mpval = initial_state;
         }
    }

    ~boolean_switch()
    {
        if(mpval)
        {
          *mpval = !(*mpval);
        }
    }
}

class my_class
{
   public:

   void function_a()
   {
      boolean_switch run_switch(&run, true);

      if( condition1 ... )
      {
          return;
      }

      if( condition2... )
      {
          return;
      }

      switch( condition 3 )
      {
         case a:
         break;

         case b:
         break;

         default:
         return;
      }
   }

   bool is_running() const
   {
      return run;
   }

   protected:

   bool run;
}

So now you get the basic idea, using the inherent nature of objects (construction & destruction) and scopes to maintain states. The usage section shows a different implementation using std::bitset for more extensibility, the idea remains the same.

Using the Code

Step 1: Define possible states for your function and enumerate them as shown below:

namespace states
{
    enum{status_running=0, status_scope1, status_scope2}
}

Step 2: Include a std::bitset object in your class as a member object. This serves the purpose of a bit mask.

namespace states
{
    enum{status_running=0, status_scope1, status_scope2}
}

const UINT MASK_SIZE 8;

class my_object
{
public:

    void function_a();

protected:
    std::bitset<mask_size> bmask;
}

Step 3: Use the switch object to indicate function scopes. Like any electrical switch, there's an 'On' and 'Off' position for the switch. Normally you'd set a switch to the 'On' position to indicate a state, but if a reverse logic is required, you may set the switch to the 'Off' position. The 'On' and 'Off' are contained in an enum within the 'switches' namespace. For the function below, we'll set the 'running' state to 'On' within the scope of the function.

void my_object::function_a()
{
    //
    // indicates the function is running now.
    //

    switches::bit_switch<mask_size> current_state(&bmask, states::status_running);

    while(//some condition)
    {
        //
        // indicates the function is within scope 1 now
        //
        switches::bit_switch<mask_size> current_state(&bmask, states::status_scope1);
        .
        .
        .

    }
}

Step 4: Add accessor functions for state checking.

namespace states
{
    enum{status_running=0, status_scope1, status_scope2}
}

const UINT MASK_SIZE 8;

class my_object
{
public:

    void function_a();

    bool is_running(){  return bmask[states::status_running];   }
    bool is_within_scope1(){    return bmask[states::status_scope1];    }
    bool is_within_scope2(){    return bmask[states::status_scope2];    }

protected:
    std::bitset<mask_size> bmask;
}

The switch is turned on when the function enters scope and turned off when it leaves its scope.

History

  • 5/12/2011 - Revision 1
推荐.NET配套的通用数据层ORM框架:CYQ.Data 通用数据层框架
新浪微博粉丝精灵,刷粉丝、刷评论、刷转发、企业商家微博营销必备工具"