2

我们正在一个编译器不支持 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,因此我们需要将object1andobject2放在函数头中,这很糟糕,因为我们应该将它放在我们需要使用的地方。并且添加 {} 来创建局部作用域是行不通的,因为清理代码需要使用局部变量。

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

4

3 回答 3

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如果你可以使用 Boost,或者只是编写你自己的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(); }
};
于 2013-09-05T09:40:42.887 回答
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;
}

但是,并不总是可以像上面那样清楚地表达代码。但当它出现时,我觉得它很棒。它的优点是将(就像 a 一样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;
}
于 2013-09-05T09:09:05.273 回答
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*/
于 2013-09-05T09:32:55.920 回答