亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

為什么應該保守地使用例外?

為什么應該保守地使用例外?

C++
一只名叫tom的貓 2019-10-24 13:47:05
我經??吹?聽到人們說例外情況應該很少使用,而永遠不要解釋原因。盡管這可能是正確的,但基本原理通常是一個輕浮的說法:“由于某種原因,它被稱為例外”,對我而言,這似乎是一種受尊敬的程序員/工程師不應接受的解釋??梢允褂卯惓=鉀Q一系列問題。為什么將它們用于控制流是不明智的?對它們的使用格外保守的背后的哲學是什么?語義學?性能?復雜?美學?慣例?我以前看過一些性能分析,但分析的水平與某些系統相關,而與其他系統無關。同樣,我不一定不同意在特殊情況下應該保存它們,但是我想知道共識的基礎是什么(如果存在這種情況)。
查看完整描述

3 回答

?
桃花長相依

TA貢獻1860條經驗 獲得超8個贊

盡管“在特殊情況下拋出異?!笔且粋€很好的答案,但您實際上可以定義這些情況是什么:當滿足先決條件而不能滿足后置條件時。這使您可以編寫更嚴格,更嚴格和更有用的后置條件,而無需犧牲錯誤處理;否則,您必須毫無例外地更改后置條件,以允許所有可能的錯誤狀態。


調用函數之前,前提條件必須為true 。

后置條件是功能保證什么之后就返回。

異常安全性說明異常如何影響函數或數據結構的內部一致性,并經常處理從外部傳入的行為(例如函子,模板參數的ctor等)。

建設者

關于可以用C ++編寫的每個類的每個構造函數,您幾乎沒有什么要說的,但是有幾件事。其中最主要的是構造的對象(即構造函數返回成功的對象)將被破壞。 您無法修改此后置條件,因為該語言假定該條件是正確的,并將自動調用析構函數。 (從技術上講,您可以接受未定義行為的可能性,該語言對此不作任何保證,但這在其他地方可能會更好地涵蓋。)


當構造函數無法成功時引發異常的唯一替代方法是修改類的基本定義(“類不變”)以允許有效的“ null”或僵尸狀態,從而允許構造函數通過構造僵尸來“成功” 。


僵尸的例子

這種僵尸修改的示例是std :: ifstream,您必須始終檢查其狀態才能使用它。例如,因為std :: string不存在,所以始終保證您可以在構造后立即使用它。想象一下,如果您必須編寫如本例所示的代碼,并且如果忘記了檢查僵尸狀態,那么您要么默默地得到不正確的結果,要么會破壞程序的其他部分:


string s = "abc";

if (s.memory_allocation_succeeded()) {

  do_something_with(s); // etc.

}

甚至命名該方法也是一個很好的例子,說明如何必須為情況字符串修改類的不變式和接口,而無法預測或處理自身。


驗證輸入示例

我們來看一個常見的例子:驗證用戶輸入。僅僅因為我們要允許失敗的輸入并不意味著解析函數需要在其后置條件中包括該內容。但是,這確實意味著我們的處理程序需要檢查解析器是否失敗。


// boost::lexical_cast<int>() is the parsing function here

void show_square() {

  using namespace std;

  assert(cin); // precondition for show_square()

  cout << "Enter a number: ";

  string line;

  if (!getline(cin, line)) { // EOF on cin

    // error handling omitted, that EOF will not be reached is considered

    // part of the precondition for this function for the sake of example

    //

    // note: the below Python version throws an EOFError from raw_input

    //  in this case, and handling this situation is the only difference

    //  between the two

  }

  int n;

  try {

    n = boost::lexical_cast<int>(line);

    // lexical_cast returns an int

    // if line == "abc", it obviously cannot meet that postcondition

  }

  catch (boost::bad_lexical_cast&) {

    cout << "I can't do that, Dave.\n";

    return;

  }

  cout << n * n << '\n';

}

不幸的是,這顯示了兩個示例,這些示例說明C ++的作用域如何要求您破壞RAII / SBRM。Python中沒有這個問題的示例,顯示了我希望C ++擁有的一些東西– try-else:


# int() is the parsing "function" here

def show_square():

  line = raw_input("Enter a number: ") # same precondition as above

  # however, here raw_input will throw an exception instead of us

  # using assert

  try:

    n = int(line)

  except ValueError:

    print "I can't do that, Dave."

  else:

    print n * n

前提條件

前提條件不必嚴格檢查-違反前提條件總是表示邏輯失敗,這是調用方的責任-但如果您檢查了前提條件,則拋出異常是適當的。(在某些情況下,返回垃圾或使程序崩潰更合適;盡管這些動作在其他情況下可能是非常錯誤的。如何最好地處理未定義的行為是另一個主題。)


特別是,請對比一下stdlib異常層次結構的std :: logic_error和std :: runtime_error分支。前者通常用于違反先決條件,而后者更適合于違反先決條件。


查看完整回答
反對 回復 2019-10-24
?
莫回無

TA貢獻1865條經驗 獲得超7個贊

  1. 昂貴的 
    內核調用(或其他系統API調用)來管理內核(系統)信號接口

  2. 難以分析語句中的
    許多問題都goto適用于異常。它們經常跳過多個例程和源文件中潛在的大量代碼。通過閱讀中間源代碼,這并不總是顯而易見的。(使用Java。)

  3. 中間代碼并不總能預料
    到被跳過的代碼在編寫或未編寫時都會考慮到異常退出的可能性。如果最初是這樣寫的,那么可能不會考慮到這一點。想一想:內存泄漏,文件描述符泄漏,套接字泄漏,誰知道?

  4. 維護的復雜性
    維護在處理異常周圍跳躍的代碼更加困難。


查看完整回答
反對 回復 2019-10-24
  • 3 回答
  • 0 關注
  • 390 瀏覽

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號