开发者

How to implement final conditions properly?

This is what I'm trying to do (this is a simplification of a real project):

int param;
int result;
void isolated(int p) {
  param = p;
  try {
    // make calculations with "param"开发者_运维技巧 and place the
    // result into "result"
    process();
  } catch (...) {
    throw "problems..";
  }
}

I can't change the way process() works, since this function is not created in the project and is a third-party function. It works with global variables param and result and we can't change this.

The problem appears when isolated() is called back from process() with another parameter. I want to catch this situation, but don't know how to do it, since finally is absent in C++. I feel that I should use RAII technique, but can't figure out how to do it in this case properly.

This is how I can make it with code duplication:

int param;
int result;
void isolated(int p) {
  static bool running;
  if (running) {
    throw "you can't call isolated() from itself!";
  }
  running = true;
  param = p;
  try {
    // make calculations with "param" and place the
    // result into "result"
    process();
    running = false;
  } catch (...) {
    running = false; // duplication!
    throw "problems..";
  }
}


"finally" like situations are handled in C++ using guard objects, that do their finally thing in the destructor. This is IMHO much more powerful approach, because you have to analyze the situation to finalize in order to create a reuseable object. In this case, we need to make process rentrant, because parameters and returns are passed in globals. The solution is to save their values on entry and restore them on exit:

template<class T>
class restorer 
{
 T &var; // this is the variable we want to save/restore
 T old_value; // the old value
 restorer(const restorer&); 
 void operator=(const restorer&); 
 public:
 restorer(T &v) : var(v), old_value(v) {}
 ~restorer() { var=old_value; }
};

int param;
int result;
int isolated(int p) {
  restorer<int> rest_param(param);
  restorer<int> rest_result(result);

  param = p;
  try {
    // make calculations with "param" and place the
    // result into "result"
    process();
    return result;
  } catch (...) {
    return 0;
  }
}


Maybe I didn't get it right, but why don't you use a flag? You want to know when the isolated() is called from the process(), right?

int isolated(int p) {
    static int execDeep = 0;
    execDeep++;

    // your code here

    execDeep--; 
}

Now you can check 'execDeep' value, > 1 means it is called from the process() while still being executed.


I still don't quite sure how finally is related here, but you could try Boost.ScopeExit if you want to avoid creating a scope guard structure yourself.

Example:

#include <boost/scope_exit.hpp>
#include <cstdio>

int isolated(int p) {
    static bool running = false;
    if (running) {
        printf("Throwing %d\n", p);
        throw p;
    }
    printf("Starting %d\n", p);
    running = true;
    BOOST_SCOPE_EXIT( (p)(&running) ) {   // <--
        printf("Stopping %d\n", p);       // <--
        running = false;                  // <--
    } BOOST_SCOPE_EXIT_END                // <--

    // ...
    if (p)
        isolated(p*10);
    // ...
    printf("Returing %d\n", p);

    return 4;
}

int main() {
    printf(">> first\n");
    isolated(0);
    printf(">> second\n");
    try {
        isolated(1);
        printf(">> third (should not be printed.)\n");  
    } catch(int p) {
        printf("Caught %d\n", p);
    }
    isolated(0);
    printf(">> fourth\n");

    return 0;
}

Result:

>> first
Starting 0
Returing 0
Stopping 0
>> second
Starting 1
Throwing 10
Stopping 1
Caught 10
Starting 0
Returing 0
Stopping 0
>> fourth


Could this work?

int save = -10000000000;
int param;
int result;

int isolated(int p) {

  if (save != -10000000000)
  {  
    // run the other condition
  }
  else
  {  
     save  = p;
     param = p;
     try {
        // make calculations with "param" and place the
        // result into "result"
        process();
        return result;
     } catch (...) {
       return 0;
     }
  }
}


If I understand correctly, you want to automatically set the running flag to false at the end of function. If that is the requirement then you can use the ScopeGuard approarch mentioned in the link.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜