6

c++ブーストライブラリを使い始めたばかりです。私は多くの場所で、scoped_ptrを使用すると、例外が発生した場合でもオブジェクトが常に破棄されることを読みました。

これらは、適切なタイミングでポイントされたオブジェクトを自動的に削除することを除いて、組み込みのC++ポインタとほとんど同じように動作します。スマートポインタは、動的に割り当てられたオブジェクトを適切に破棄できるため、例外が発生した場合に特に役立ちます。

次のコードで試してみました。

#include<boost/scoped_ptr.hpp>

class B
{
  public:
    B(){ std::cout<< "B constructor call\n"; }
    ~B(){ std::cout<<"B destructor call\n"; }
};

class A
{
  public:
  boost::scoped_ptr<B> b;
  A():b(new B())  
  {
    throw 1;
  }
};

int main()
{
    A a; return 0;
}

output:
B constructor call
terminate called after throwing an instance of 'int'
Aborted (core dumped)

Bのデストラクタへの呼び出しはありません。しかし、scoped_ptrを使用したので、Bのデストラクタを呼び出す必要があったか、scoped_ptrの使用を誤って解釈しました。

しかし、それをtry catchで囲むと、Bのデストラクタが呼び出されます。

try{
  A a;
} catch( ... ) {
}

この場合、tryブロックで例外が発生した場合に、ローカルに割り当てられたすべてのオブジェクトがスタックから削除され、scoped_ptrのオブジェクトが内部にラップされているため、スコープオブジェクトのデストラクタが最終的にポインタを破棄すると、Aのデストラクタが呼び出されます。 。割り当てられたメモリを明示的に削除する必要がないか、scoped_ptrの説明を誤って解釈したため、scoped_ptrは便利です。

scoped_ptrを使用して例外が発生した場合に、クラスBのデストラクタを呼び出すにはどうすればよいですか。

4

2 に答える 2

15

一致する例外ハンドラーがないため、std::terminate直接呼び出されます。この場合、スタックはアンワインドされません。そのキャッチにtry/catchを入れると、そのハンドラーが再スローされた場合でも、デストラクタの呼び出しが表示されます。mainint

C++11§15.1/2:

例外がスローされると、制御は一致するタイプの最も近いハンドラーに転送されます。「最も近い」とは、キーワードに続く複合ステートメントまたはctor-initializertryが制御スレッドによって最後に入力され、まだ終了していないハンドラーを意味します。

および§15.3/9:

一致するハンドラーが見つからない場合、関数std::terminate()が呼び出されます。std::terminate()この呼び出しが実装定義される前にスタックが巻き戻されるかどうか。

オンラインデモ

于 2012-10-14T23:27:41.340 に答える
0

C ++は、スタックを巻き戻すときにローカル変数を破棄します(キーワードまたは例外のいずれかを使用して関数から戻るreturn)ので、を破棄するものが表示されるはずscoped_ptrです。ただし、特別な場合には、C ++がスタックを巻き戻す前に、例外が呼び出されてプログラムが強制終了されますmainterminate

void test() {throw 1;}
void main() {
    string sMain;
    test();
}

上記の例でsMainは、例外が呼び出しを引き起こすため、は破棄されませんterminate

sMain constructed
exception occurred: main has no where to go, and it has no handler to handle
    the exception, so it will call `terminate`, but wait we are still at `main`
    so we have no stack unwinding here and sMain will never destroyed!!
于 2012-10-14T23:58:40.637 に答える