3

私は例外でメモリの割り当てを解除していない以下のようなスマートポインタの実装を持っています..

template <class T>
class SMARTPOINTER
{
public:
   SMARTPOINTER(T* pointee) : SMART_POINTEE(pointee) {
    cout <<"\n Inside class SMARTPOINTER CONSTURCTOR \n";
   }

   ~SMARTPOINTER() {
     cout <<"\n Inside class SMARTPOINTER DESTRUCTOR \n";
      delete SMART_POINTEE;
   }

   T& operator*() const
   {
      cout <<"\n Inside class SMARTPOINTER operator* \n";
      return *SMART_POINTEE;
   }

   T* operator->() const
   {
      cout <<"\n Inside class SMARTPOINTER operator->()  \n";
      return SMART_POINTEE;
   }

private:
   T* SMART_POINTEE;

};

class Widget
{
public:

  Widget() {
      cout <<"\n Inside Widget CONSTRUCTOR \n";
  }

   void Fun() { 
     cout <<"\n Inside Widget::Fun() \n";
   }

  ~Widget() {
      cout <<"\n Inside Widget DESTRUCTOR \n";
  }

};

class THROWME{

};

int main() {

SMARTPOINTER<Widget> sp(new Widget);
sp->Fun();
throw new THROWME;
(*sp).Fun();

return 0 ;
}

出力が

Inside Widget CONSTRUCTOR 

 Inside class SMARTPOINTER CONSTURCTOR 

 Inside class SMARTPOINTER operator->()  

 Inside Widget::Fun() 
uncaught exception of type THROWME*
Aborted.

私の知る限り、スマートポインターはそのような場合に役立つはずです!! smart pointer を介して呼び出される Widget の破壊が見つかりません。

したがって、ここでいくつかの実装が欠落しているに違いありません。

コメントを読んだ後に編集

try catch で結果が得られました。しかし、その正しいアプローチがコードで変更されるかどうかはまだわかりません

  int main() {
        try {
        SMARTPOINTER<Widget> sp(new Widget);
        sp->Fun();
        THROWME tm;
        throw tm;
        (*sp).Fun();
        }
        catch(...) {
          cout <<"\n **SOME EXCEPTION CAUGHT**  \n";
        }
        return 0 ;
        }

結果

 Inside Widget CONSTRUCTOR 

 Inside class SMARTPOINTER CONSTURCTOR 

 Inside class SMARTPOINTER operator->()  

 Inside Widget::Fun() 

 Inside class SMARTPOINTER DESTRUCTOR 

 Inside Widget DESTRUCTOR 

 **SOME EXCEPTION CAUGHT**
4

2 に答える 2

4

デストラクタの呼び出しは、スタックの巻き戻しの一部であり、例外がコールスタックを「バブルアップ」するときに行われます...例外が処理されない場合を除きます。その場合、スタックが巻き戻されるかどうかは実装定義です:

プログラム内に一致するハンドラが見つからない場合は、関数terminate()( except.terminate) が呼び出されます。呼び出し前にスタックがアンワインドされるかどうかterminate()は実装定義です。

これをより適切に処理するには、関数の try ブロックを使用できます。

int main()
try {
  // main body
} catch (...) {
  std::cerr << "Unhandled exception\n";
  std::terminate();
}

... ただし、これにより例外が飲み込まれ、デバッグが難しくなります。

于 2013-06-01T08:46:09.613 に答える
4

未処理の例外が呼び出されるため、デストラクタは呼び出されませTHROWMEstd::terminateこの質問、特に受け入れられた回答の最初の引用も参照してください。

C++11 15.2 コンストラクタとデストラクタ [except.ctor]

1 コントロールが throw 式からハンドラーに渡されると、try ブロックに入ってから構築されたすべての自動オブジェクトに対してデストラクタが呼び出されます。自動オブジェクトは、構築完了の逆の順序で破壊されます。

例外を処理するための try ブロックがないため、デストラクタは呼び出されません。

于 2013-06-01T08:37:51.387 に答える