如何构建清理代码?

时间:2013-09-05 08:55:21

标签: c++ c

我们正在一个平台上开发应用程序,该平台的编译器不支持C ++语言中的异常。

当我们调用API时,我们需要检查返回结果中的错误代码。有时我们需要在发生错误时进行一些清理。我们定义一个宏CHECK_ERROR_GOTO来检查错误代码。所以像这样的代码。

int res = callAPI1();
CHECK_ERROR_GOTO(res, cleanup);
A* object1 = callAPI2();    // HERE WE WILL GET ERROR, 
                             //BECAUSE GOTO SKIP INITIALIZATION OF OBJECT1
CHECK_ERROR_GOTO(object1 == NULL, cleanup);
C* object2 = callAPI3(object2);
CHECK_ERROR_GOTO(object2 == NULL, cleanup)
return 0;
cleanup:
    //Cleanup code here.
    delete object1
    delete object2

如代码所示,我们将通过goto跳过初始化的object1,因此我们需要在函数的头部放置object1object2,这很糟糕,因为我们应该把它放在我们的位置需要使用。并且添加{}来创建局部作用域不起作用,因为清理代码需要使用局部变量。

所以无论如何我们可以安排代码,所以我们不需要在函数的开头放置变量初始化吗?

3 个答案:

答案 0 :(得分:2)

您说您的编译器不支持异常。但它是否支持在早期返回时执行析构函数?我当然希望它能做到。你应该通过一个简单的测试来确保。

这意味着您可以使用智能指针和其他在析构函数中释放资源的类。

int res = callAPI1();
if (!res) return -1;
scoped_ptr<A> object1(callAPI2());
if (!object1) return -1;
scoped_ptr<C> object2(callAPI3(object1.get()));
if ((!object2) return -1;
return 0;

scoped_ptr这里可以是任何合适的智能指针类:你的编译器unique_ptr在不太可能的情况下是支持它,auto_ptr如果你感到勇敢,boost::scoped_ptr如果scoped_ptr,这非常简单。

template <typename T>
class scoped_ptr {
  T* raw;

  struct bool_dummy { void fn() {} };
  typedef void (bool_dummy::*pseudo_bool)();

  scoped_ptr(const scoped_ptr&); // non-copyable
  scoped_ptr& operator =(const scoped_ptr&);

public:
  scoped_ptr(T* raw) : raw(raw) {}
  ~scoped_ptr() { delete raw; }

  T* get() const { return raw; }
  T& operator *() const { return *get(); }
  T* operator ->() const { return get(); }
  operator pseudo_bool() const { return get() ? &bool_dummy::fn : 0; }
  bool operator !() const { return !get(); }
};

答案 1 :(得分:0)

我喜欢这样做:

int foo()
{
  A* object1 = 0; // make sure you initialize those two
  C* object2 = 0; // so that further delete calls always work

  for (;;)
  {
    int res = callAPI1();
    if (res == -1)
      break;

    object1 = callAPI2();
    if (object1 == 0)
      break;

    object2 = callAPI3(object1);
    if (object2 == 0)
      break;

    return 0;
  }

  delete object1;
  delete object2;

  return -1;
}

然而,并不总是可以像上面那样清楚地表达代码。但是当它发生时,我发现它很棒。它的优点是可以在一个地方放置(就像一个goto)清理代码。否则它可能变得不可维护,如:

// don't do this:
if(object2==0)
{
  delete object1;
  return 0;
}
// ... more code ...
if(object3==0)
{
  delete object2;
  delete object1;
  return 0;
}
// ... more code ...
if(object4==0)
{
  delete object3
  delete object2;
  delete object1;
  return 0;
}

答案 2 :(得分:0)

是的,不是最美丽的代码,但它会:

int res = callAPI1();
if (!res) /* inverse of CHECK_ERROR_GOTO(res, cleanup); ??? */
{
    A * object1 = callAPI2();

    if (object1 != null) /* inverse of CHECK_ERROR_GOTO(object1 == NULL, cleanup); */
    {
        C * object2 = callAPI3(object1); //I suppose you want object1 here and not 2

        if (object2 != null) /* inverse of CHECK_ERROR_GOTO(object2 == NULL, cleanup);*/
        {
            /* if we reached here then both object1 and 2 are created
               thus delete both before returning to not get any memory leaks */
            delete object1;
            delete object2;

            return 0;
        }

        /* if we reached here then the creation of object2 has failed.
           Only delete object1 because object2 is not initialized. */
        delete object1;

        /* do some kind of return here? like -3 */
    }


    /* do some kind of return here? like -2 */
}

/* do some kind of return here? like -1*/