程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> C++語言中使用setjmp與longjmp的注意點

C++語言中使用setjmp與longjmp的注意點

編輯:關於C語言
 

“setjmp和longjmp並不能很好地支持C++中面向對象的語義。因此在C++程序中,請使用C++提供的異常處理機制”。它在MSDN中的原文如下:

  setjmp and longjmp do not support C++ object semantics. In C++ programs, use the C++ exception-handling mechanism.

  這究竟是為什麼?大家知道,C++語言中是基本兼容C語言中的語義的。但是為什麼,在C++程序中,唯獨卻不能使用C語言中的異常處理機制?雖然大家都知道,在C++程序中,實際上是沒有必要這麼做,因為C++語言中提供了更完善的異常處理模型。但是,在許多種特殊情況下,C++語言來開發的應用程序系統中,可能采用了C語言中的異常處理機制。例如說,一個應用程序由於采用C++開發,它裡面使用了C++提供的異常處理機制;但是它可能需要調用其它已經由C語言實現的程序庫,而恰恰在這個被復用的程序庫中,它也采用了異常處理機制。因此對於整個應用程序系統而言,它不可避免地出現了這種矛盾的局面。並且這種情況是非常多見的,也可能是非常危險的。因為畢竟,“setjmp and longjmp do not support C++ object semantics”。所以,我們非常有必要來了解它究竟為什麼不會兼容。

  在本篇文章中,主人公阿愚將和程序員朋友們一起,深入探討setjmp與longjmp機制,為什麼它很難與C++和睦相處?另外還有,如果C++語言來開發的應用程序系統中,不得不同時使用這兩種異常處理模型時,又如何來盡可能保證程序系統的安全?

  C++語言中使用setjmp與longjmp

  閒話少說,還是看例程先吧!代碼如下:

  // 注意,這是一個C++程序。文件擴展名應該為.cpp或其它等。例如,c++setjmp.cpp

  #include

  #include

  #include

  //定義一個測試類

  class MyTest

  {

  public:

  MyTest ()

  {

  printf("構造一個MyTest類型的對象\n");

  }

  virtual ~ MyTest ()

  {

  printf("析構銷毀一個MyTest類型的對象\n");

  }

  };

  jmp_buf mark;

  void test1()

  {

  // 注意,這裡拋出異常

  longjmp(mark, 1);

  }

  void test()

  {

  test1();

  }

  void main( void )

  {

  int jmpret;

  // 設置好異常出現時,程序的回溯點

  jmpret = setjmp( mark );

  if( jmpret == 0 )

  {

  // 建立一個對像

  MyTest myobj;

  test();

  }

  else

  {

  printf("捕獲到一個異常\n");

  }

  }

  請編譯運行一下,程序的運行結果如下:

  構造一個MyTest類型的對象

  析構銷毀一個MyTest類型的對象

  捕獲到一個異常

  上面的程序運行結果,那麼到底是不是合理的呢?阿愚感到有些納悶,這結果肯定是合乎情理的呀!從這個例程來看,setjmp和longjmp並不能破壞C++中面向對象的語義,它們之間融洽得很好呀!那麼為什麼會說,“setjmp and longjmp do not support C++ object semantics”。請不要著急,沉住氣!繼續看看其它的情況,代碼如下:

  #include

  #include

  #include

  class MyTest

  {

  public:

  MyTest ()

  {

  printf("構造一個MyTest類型的對象\n");

  }

  virtual ~ MyTest ()

  {

  printf("析構銷毀一個MyTest類型的對象\n");

  }

  };

  jmp_buf mark;

  void test1()

  {

  // 注意,這裡在上面程序的基礎上,進行了一點小小的改動

  // 把對像的構造挪到這裡來

  MyTest myobj;

  longjmp(mark, 1);

  }

  void test()

  {

  test1();

  }

  void main( void )

  {

  int jmpret;

  jmpret = setjmp( mark );

  if( jmpret == 0 )

  {

  test();

  }

  else

  {

  printf("捕獲到一個異常\n");

  }

  }

  同樣也編譯運行一下,看程序的運行結果,如下:

  構造一個MyTest類型的對象

  捕獲到一個異常

  呵呵!那個對像的構造建立過程只不過是被稍稍挪了一下位置,而且先後順序還沒有改變,都是在if( jmpret == 0 )語句之後,longjmp(mark, 1)之前。可為什麼程序運行的結果卻不同了呢?顯然,從這個例程的運行結果來看,setjmp和longjmp已經破壞C++中面向對象的語義,因為那個MyTest類型的對像只被構造了,但是它卻沒有被析構銷毀!這與大家所知道的面向對象的理論是相違背的。程序員朋友們,不要小看這個問題,有時這種錯誤將給應用程序系統帶來極大的災難(不僅僅是內存資源得不到釋放,更糟糕的是可能引發系統死鎖或程序崩潰)。

  由此可以看出,setjmp與longjmp機制,有時的確是不能夠與C++和睦相處。那麼,為什麼第1個例子中會安然無恙呢?它有什麼規律嗎?請繼續看另外的一個例子,代碼如下:

  #include

  #include

  #include

  class MyTest

  {

  public:

  MyTest ()

  {

  printf("構造一個MyTest類型的對象\n");

  }

  virtual ~ MyTest ()

  {

  printf("析構銷毀一個MyTest類型的對象\n");

  }

  };

  jmp_buf mark;

  void test1()

  {

  longjmp(mark, 1);

  }

 
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved