1

スタック上のオブジェクトのスコープを介してスローされた特定の例外のためにスタックが巻き戻されているため、デストラクタが呼び出されているときにデストラクタがいくつかの作業をスキップするようにしたいスタック上のオブジェクトがあります。

これで、スタック アイテムのスコープ内に try catch ブロックを追加し、問題の例外をキャッチして、スキップする作業を実行しないようにスタック オブジェクトに通知し、次のように例外を再スローすることができます。

RAII_Class pending;

try {
  doSomeWorkThatMayThrowException();
} catch (exceptionToSkipPendingDtor &err) {
  pending.notifySkipResourceRelease();
  throw;
}

ただし、これを行うためのよりエレガントな方法があることを願っています。たとえば、次のように想像してください。

RAII_Class::~RAII_Class {
  if (detectExceptionToSkipPendingDtorBeingThrown()) {
    return;
  }
  releaseResource();
}
4

7 に答える 7

8

でこれをほぼ実行できますがstd::uncaught_exception()、完全ではありません。

ハーブ・サッターは、私よりも「ほぼ」うまく説明しています: http://www.gotw.ca/gotw/047.htm

デストラクタから呼び出されたときに true を返すまれなケースがありstd::uncaught_exception()ますが、問題のオブジェクトはスタックの巻き戻しプロセスによって実際には破棄されていません。

RAII はユース ケースに合わないため、おそらく RAII を使用しない方がよいでしょう。RAII は常にクリーンアップすることを意味します。例外かどうか。

あなたが望むのはもっと簡単です: 単純な関数のシーケンスである例外がスローされない場合にのみ、リソースを解放します。

explicitAllocateResource();
doSomeWorkThatMayThrowException();
explicitReleaseResource(); // skipped if an exception is thrown
                           // by the previous function.
于 2010-07-23T23:36:31.507 に答える
5

私は逆の方法でそれを行います-例外がスローされなかった場合は、その作業を行うように明示的に指示します:

RAII_Class pending;

doSomeWorkThatMayThrowException();

pending.commit(); // do or prepare actual work
于 2010-07-23T23:38:51.240 に答える
3

これは、RAII を使用する主な理由を回避しているようです。RAII のポイントは、コードの途中で例外が発生した場合でも、リソースを解放したり、適切に破棄したりできることです。

これが必要なセマンティックでない場合は、RAII を使用しないでください。

したがって、代わりに:

void myFunction() {
    WrapperClass wc(acquireResource());

    // code that may throw
}

ただ行う:

void myFunction() {
    Resource r = acquireResource();

    // code that may throw

    freeResource(r);
}

途中のコードがスローされた場合、リソースは解放されません。これは、RAII を保持する (および名前を保持する) のではなく、RAII のセマンティクスを実装しないことです。

于 2010-07-23T23:51:43.813 に答える
0

bool std::uncaught_exception(); のように見えます。特別な例外だけでなく、すべての例外に対してこの動作をさせたい場合は、トリックを行います!

于 2010-07-23T23:40:24.040 に答える
0

try-catch なしで実行できます。

RAII_Class pending;
doSomeWorkThatMayThrowException();  // intentional: don't release if throw
pending.releaseResource();

あるいは、RAII をもう少し試してみることもできます。

struct RAII_Class {
    template<class Op>
    void execute(Op op) {
        op();
        releaseResources();
    }

private:
    void releaseResources() { /* ... */ }
};

int main(int argc, char* argv[])
{
    RAII_Class().execute(doSomeWorkThatMayThrowException);
    return 0;
}
于 2010-07-23T23:44:15.080 に答える
0

せいぜい大したことではありませんが、関心のある例外クラスのコードを所有している場合は、オブジェクトのコンストラクターで「true」に設定される静的データメンバーをそのクラス (bool) に追加できます。そのクラスの、およびデストラクタで false (代わりにインクリメント/デクリメントする int である必要がある場合があります)。次に、RAII クラスのデストラクタで std::uncaught_exception() をチェックし、true の場合は、例外クラスの静的データ メンバーをクエリします。true (または > 0) が返された場合、これらの例外の 1 つが発生しています。それ以外の場合は無視します。

あまりエレガントではありませんが、おそらくうまくいくでしょう(複数のスレッドがない限り)。

于 2010-07-24T00:51:45.483 に答える
0

std::uncaught_exception() に関する興味深い議論と、私にとってはるかにエレガントで正しいと思われるあなたの質問に対する代替ソリューションを含むこのWebサイトを見つけました。

http://www.gotw.ca/gotw/047.htm

//  Alternative right solution
//
T::Close() {
  // ... code that could throw ...
}

T::~T() /* throw() */ {
  try {
    Close();
  } catch( ... ) {
  }
}

このようにして、デストラクタは1つのことだけを行い、例外中に例外をスローすることから保護されます(これは、解決しようとしている問題だと思います)。

于 2010-07-23T23:53:57.537 に答える