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;
}

ただし、上記のようにコードを明確に表現できるとは限りません。しかし、そうである場合、私はそれが素晴らしいと思います。gotoクリーンアップ コードを ( のように) 1 か所に配置できるという利点があります。そうしないと、次のように保守できなくなる可能性があります。

// 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 に答える