<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Exception Handling Considered Harmful

      異常處理
      被認為存在缺陷

      Do, or do not. There is no try.

      — Yoda, The Empire Strikes Back
      (George Lucas)

      by Jason Robert Carey Patterson, Nov 2005

      Recent programming languages such as Java, Python and Ruby have chosen to use exception handling as their primary method of error handling, replacing the traditional approach of error return codes. I believe continuing this trend for future programming languages would be a mistake, for two reasons...

      最近的編程語言如 Java, Python 和 Ruby 選擇使用異常處理(exception handling)作為其主要的錯誤處理方法, 取代了傳統的返回錯誤碼方法. 我相信在未來的編程語言中繼續這種趨勢將是一個錯誤, 原因有兩個...

      1. Exception handling introduces a hidden, "out-of-band" control-flow possibility at essentially every line of code. Such a hidden control transfer possibility is all too easy for programmers to overlook – even experts. When such an oversight occurs, and an exception is then thrown, program state can quickly become corrupt, inconsistent and/or difficult to predict (think about an exception unexpectedly being thrown part way through modifying a large data structure, for example).
      2. 異常處理在幾乎每一行代碼中引入了一種隱藏的"帶外(out-of-band, 流程之外)"控制流可能性. 這種隱藏的控制轉移可能性對于程序員來說太容易忽視了 – 即使是專家. 當這種疏忽發生, 然后拋出異常時, 程序狀態會很快變得損壞, 不一致 和/或 難以預測(例如, 考慮在修改大型數據結構的過程中意外拋出異常).
      3. Exception handling does not fit well with most of the highly parallel programming models currently in use or being explored (fork/join, thread pools and task queues, the CSP/actor model etc), because exception handling essentially advocates a kind of single-threaded "rollback" approach to error handling, where the path of execution – implicitly a single path – is traversed in reverse by unwinding the call stack to find the appropriate error handling code.
      4. 異常處理不太適合于目前使用或正在探索的大多數高效的并行編程模型 (fork/join, 線程池和任務隊列, CSP/actor 模型等), 因為異常處理本質上提倡一種單線程錯誤處理的 "回滾(rollback)" 方法,其中執行路徑 – 隱含的 一條 路徑 – 通過展開調用堆棧反向遍歷找到適當的錯誤處理代碼.

      Good Intentions

      好的意圖

      Exception handling was originally intended to solve several perceived problems with the traditional approach of error handling via return codes.

      異常處理最初旨在通過返回碼來解決傳統錯誤處理方法的幾個感知問題.

      First, by separating the error handling code from the main body of normal code, it was hoped that the code would be less cluttered, and hence cleaner, with the normal, non-error case easier to follow because it was not obscured by necessary but tedious and unlikely error checking/handling.

      首先, 通過將錯誤處理代碼與正常業務代碼分離, 希望代碼不會那么混亂, 因此 更干凈, 正常的, 非錯誤的情況更容易理解, 因此他沒有必要的, 但繁瑣的且不太常見的錯誤檢查/處理.

      Second, by allowing a separation between the point where an error occurs and the point where it is handled, even a potentially very large separation across many function calls, it was hoped to enable better handling of errors deep within libraries, allowing those errors to be propagated back to the application without requiring a whole chain of error checking and returning code to be written, and thus avoiding the tendency for libraries to swallow or generalize errors because it was too much hassle to feed them all the way back in full detail.

      其次, 通過允許在發生錯誤的點和處理錯誤的點之間進行分離, 甚至在許多函數調用之間可能存在非常深的調用鏈, 人們希望能夠更好地處理庫深層的內部錯誤, 允許這些錯誤被傳播回上層應用程序,而不需要編寫整個錯誤檢查鏈和返回代碼, 從而避免了庫吞并或泛化錯誤的傾向, 因為一路反饋完整的細節太麻煩了.

      Finally, exceptions were seen as a solution to the "semi-predicate" problem, where for some operations every possible return value is valid and thus an error must be indicated through some other, more indirect means, such as a pass-by-reference error argument or an internal success/failure state indicator within an object.

      最后, 異常被視為 "半吊子(semi-predicate)" 問題的解決方案,其中對于某些操作, 每個可能的返回值都是有效的, 因此必須通過其他更間接的方式來指示錯誤, 例如通過引用錯誤參數或對象內部的成功/失敗狀態指示器.

      To solve these problems, exception handling essentially advocates a kind of "rollback" approach to error handling. When an error occurs an exception is "thrown", which engages the runtime system to begin a rollback operation by unwinding the call stack, destroying local objects as it goes, until a suitable error handler "catch" block is reached, and execution continues from there.

      為了解決這些問題, 異常處理本質上提倡一種錯誤處理的 "回滾" 方法. 當發生錯誤時, 會"拋出(thrown)"異常, 這會讓運行時系統通過展開調用堆棧, 銷毀本地對象來開始回滾操作, 直到到達合適的錯誤處理程序 "捕獲(catch)" 塊, 并從那里繼續執行.

      The primary intended benefit of such an approach is that all of the code between the place where the error happens and is thrown, and the place where the exception is caught and handled, can simply remain blissfully unaware of the error, and not have to detect and handle it explicitly. Local objects just get destroyed automatically while unwinding the call stack, and all is well.

      這種方法的主要預期好處是, 在錯誤發生和拋出的地方, 以及異常被捕獲和處理的地方之間的所有代碼都可以保持對錯誤非常愉快的不知道, 而不必顯式地檢測和處理他. 本地對象只是在解除調用堆棧時自動被銷毀, 一切正常.

      Sounds good, right?

      聽起來不錯, 對吧?

      Hidden Control Flow & Corrupt State

      隱藏的控制流 & 損壞狀態

      One immediately obvious problem with a "rollback" style approach to error handing is that many operations are not so trivially rolled back simply by destroying local objects (and perhaps letting heap objects be cleaned up by a garbage collector). The classic example is I/O – you cannot un-print something to the screen, un-ask for user input, un-overwrite a file's contents, or un-send a network packet. All true, and an excellent point.

      "回滾" 式錯誤處理方法的一個顯而易見的問題是, 許多操作并不是簡單地通過銷毀本地對象 (并且可能讓垃圾收集器清理堆對象) 來回滾. 典型的例子是 I/O – 你不能取消在屏幕上打印某些東西, 取消詢問用戶輸入, 取消覆蓋文件的內容, 或者取消發送網絡數據包. 都是些很常見事實.

      But that's just the tip of the iceberg. I/O isn't even the real problem. It is just one of a number of possible non-local side effects that code might have. Far more common, yet often overlooked, is state in general – any code which simply makes changes to some part of a shared data structure, like a document model or a scene graph. Unwinding the stack and destroying local objects won't undo those changes. In fact, in an exception-rich environment where the act of making such changes can potentially cause an exception, it is impossible to write a strongly exception-safe function that has two or more unrelated side effects, of any kind, that cannot be performed atomically.

      但這只是冰山一角. I/O 甚至不是真正的問題. 這只是代碼可能產生的許多非局部副作用之一. 通常情況下, 更常見但往往被忽略的是 狀態(state) – 任何只對共享數據結構的某個部分進行更改的代碼, 如文檔模型或場景圖. 展開堆棧并銷毀本地對象不會撤消這些更改. 事實上, 在一個異常豐富的環境中, 進行此類更改的行為可能會導致異常, 因此不可能編寫一個具有兩個或多個不相關副作用的強異常安全函數, 這些副作用中任何一種, 都不能以原子化執行.

      It is impossible to write a strongly exception-safe function
      that has two or more unrelated side effects, of any kind,
      that cannot be performed atomically.
      不可能編寫一個非常安全的異常函數
      同時處理好兩種或兩種以上不相關的相關副作用,
      這不能原子化地執行.

      Consider an exception unexpectedly being thrown part way through modifying a large data structure, for example. How likely is it that the programmer has written code to correctly catch that exception, undo or reverse the partial changes already made to the data structure, and re-throw the exception? Very unlikely! Far more likely is the case that the programmer simply never even considered the possibility of an exception happening in the first place, because exceptions are hidden, not indicated in the code at all. When an exception then occurs, it causes a completely unexpected control transfer to an earlier point in the program, where it is caught, handled, and execution proceeds – with a now corrupt, half-modified data structure!

      例如, 考慮通過修改大型數據結構意外地拋出異常. 程序員編寫的代碼正確捕獲該異常, 撤消或重置已對數據結構進行的部分更改并重新拋出該異常的可能性有多大? 不太可能! 更可能的情況是, 程序員根本沒有考慮異常發生的可能性, 因為異常是隱藏的, 根本沒有在代碼中指出. 當一個異常發生時, 他會導致一個完全意外的控制轉移到程序中的一個較早的點, 在那里它會被捕獲, 處理并繼續執行 – 現在可能是一個損壞的, 半修改的數據結構

      Any non-trivial shared-data-modifying algorithm cannot, in general, be truly strongly exception-safe unless either the programming language itself provides some form of transactional capability (eg: SQL's commit approach), or the programmer simulates transactional behavior in code by making a copy of the data, modifying the copy, and doing some kind of pointer swap to make the new copy the "real thing" atomically – which is ridiculously tedious and clearly not practical for large objects or complex data structures.

      一般來說, 任何非平凡的共享數據修改算法都不可能真正具有強異常安全性, 除非編程語言本身提供某種形式的事務性功能 (例如: SQL 的 commit 方法), 或者程序員通過復制數據, 修改副本來模擬代碼中的事務性行為, 并進行某種指針交換, 使新副本在原子上成為"真實的東西" – 這是非??菰锓ξ堵闊┑? 顯然不適用于大型對象或復雜的數據結構.

      So if you're in the middle of modifying data, and an exception occurs, you could easily end up leaving the data in a half-baked state. That is really, really dangerous, because it invites the possibility of silent data corruption. In most cases, any clearly visible error signal, even program termination, is by far preferable to the possibility of silent data corruption. And exception handling simply isn't a clearly visible error signal. Most of the calling code can, and does, simply ignore exceptions, assuming some code further back will catch and handle them.

      因此, 如果你正在修改數據, 并且出現異常, 那么你很容易會把數據放在半成品(half-baked, 考慮不周全, 草率的)狀態. 這 really 真的是非常危險的,因為它可能會導致數據損壞. 在大多數情況下, 任何清晰可見的錯誤信號, 甚至程序終止, 都比無聲數據損壞的可能性要好得多. 異常處理并不是一個清晰可見的錯誤信號. 大多數調用代碼可以也經常忽略異常, 并假設后面的一些代碼會將捕獲并處理他們.

      Thus, coding styles relying on exception handling over anything more than trivial distance between throw and catch have a tendency to "take simple, reproducible and easy to diagnose failures and turn them into hard-to-debug subtle corruptions", to quote Larry Osterman.

      因此, 在拋出和捕獲之間的微小距離之外, 依賴異常處理的編碼風格往往會 "將簡單, 可重復且易于診斷的故障轉化為難以調試的細微損壞", 引用 Larry Osterman.

      Forcing the calling code to handle the error right away is the correct approach, because it forces the programmer to think about the possibility of an error occurring. That's a key point. The fact that this clutters the code with error checking is unfortunate, but it is a small price to pay for correctness of operation. Exceptions tend to allow, even encourage, programmers to ignore the possibility of an error, assuming it will be magically handled by some earlier exception handler.

      強制代碼 立即 處理錯誤是正確的做法, 因為他迫使程序員 思考 發生錯誤的可能性. 這是一個關鍵點. 不幸的是, 這會使代碼中的錯誤檢查變得繁瑣, 但為操作的正確性付出的代價很小. 異常傾向于允許, 甚至鼓勵程序員忽略錯誤的可能性, 并假設他會被調用方異常處理程序神奇地處理.

      Forcing the calling code to handle the error right away is
      the correct approach, because it forces the programmer
      to think about the possibility of an error occurring.

      Exceptions tend to allow, even encourage, programmers
      to ignore the possibility of an error, assuming it will be
      magically handled by some earlier exception handler.
      強制代碼立即處理錯誤是
      正確的方法, 因為他迫使程序員
      考慮發生錯誤的可能性

      例外情況往往允許甚至鼓勵程序員
      忽略錯誤的可能性, 并假設他會
      被調用方的異常處理程序神奇地處理.

      In order to write exception-safe code, at every significant line of code the programmer must take the possibility of an exception and rollback happening into account, to be sure the code cleans up properly and leaves things in a suitable, stable state if an exception occurs – that it doesn't leave a data structure half-modified, or a file or network connection open, for example. That is decidedly non-trivial. It takes a great deal of time and effort, it requires a very high degree of discipline to get right, and it is just far too easy to forget or overlook something – even experts frequently get it wrong.

      為了編寫異常安全的代碼, 在每一行重要的代碼中, 程序員必須考慮到發生異常和回滾的可能性, 以確保代碼正確地清理, 并在發生異常時保持適當, 穩定的狀態, 例如, 不會使數據結構半修改(half-modified), 或文件或網絡連接處于打開狀態. 這絕對不是小事. 這需要花費大量的時間和精力, 需要非常嚴格的紀律才能糾正錯誤, 忘記或忽略某些事情太容易了 – 即使是專家也經常出錯.

      Putting more general issues aside for just a moment, the C++ exception handling system in particular wasn't very well thought out IMHO, and is by far the weakest part of the language – so much so that I generally recommend people don't use C++ exceptions at all, and turn them off in their compiler if possible.

      把更多的一般問題放在一旁, 特別是 C++ 異常處理系統不是很好的思考, 是目前語言中最薄弱的部分 – 所以我通常建議人們強制別使用 C++ 異常, 如果可能的話, 在編譯器中關閉他們.

      Exception handling is the only C++ language feature which requires significant support from a complex runtime system, and it's the only C++ feature that has a runtime cost even if you don't use it – sometimes as additional hidden code at every object construction, destruction, and try block entry/exit, and always by limiting what the compiler's optimizer can do, often quite significantly. Yet C++ exception specifications are not enforced at compile time anyway, so you don't even get to know that you didn't forget to handle some error case! And on a stylistic note, the exception style of error handling doesn't mesh very well with the C style of error return codes, which causes a real schism in programming styles because a great deal of C++ code must invariably call down into underlying C libraries.

      異常處理是唯一在 C++ 語言特性中, 需要復雜的運行時系統的支持, 他也是唯一的 C++ 特性,即使不使用他, 也有運行時的成本 – 有時所能做的通過限制編譯器, 為每個對象構造, 銷毀, try 代碼塊 entry/exit, 始終 添加 try catch 隱藏代碼, 在優化中通常非常重要. 然而, C++ 異常規范在編譯時沒有強制執行, 所以你甚至不知道你沒有忘記處理一些錯誤的情況! 從風格上講, 異常風格的錯誤處理與 C 風格的錯誤返回代碼非常不搭, 這會導致編程風格中的真正分裂, 因為大量 C++ 代碼必須始終調用底層 C 庫.

      Furthermore, because C++ doesn't have garbage collection it is all too easy even for experts (see here, here, here and here) to accidentally write code which leaks memory if an exception is thrown by some function you call, even if you yourself don't use exceptions. This is further complicated by C++'s lack of a finally block to simplify cleanup. It is also particularly easy in C++ to leave objects in a half-baked state when an exception occurs, because even many "primitive" operations like assignment can potentially throw exceptions. In practice, it becomes essentially impossible not to leave objects in a half-baked state once the objects grow beyond trivial size/complexity. Even many of the STL containers are not strongly exception-safe – they don't leak memory, but they might leave your data in a half-baked state where the operation was only "partially" done, which is not terribly useful or helpful.

      另外, 因為 C++ 沒有垃圾回收, 哪怕是專家也很容易(see here, here, here and here) 在調用的某個函數引發異常, 意外導致編寫代碼會引發內存泄漏 即使你自己不使用異常 . 由于 C++ 缺少簡化清理的 finally 塊, 這一點變得更加復雜. 在 C++ 中, 當異常發生時, 特別容易將對象置于半銷毀狀態, 因為即使許多"原始(primitive)"操作如賦值也可能引發異常. 在實踐中, 一旦對象的大小/復雜度超過了微不足道的程度, 就不可能不讓對象處于半成品的狀態. 甚至許多 STL 容器也不是很健壯 異常安全 – 他們不會泄漏內存, 但他們可能會讓您的數據處于半成品狀態,操作只"部分"完成, 這不是非常有用或有用

      The core problem is the hidden control-flow possibility. There's a famous joke about a mythical programming language construct called comefrom, which is a parody on the problematic goto statement found in many early programming languages. The idea is that the programmer can, at any point in the program, say "comefrom 20", and any time execution reaches line 20 it will immediately jump to the "comefrom" code. The point being made here is that nothing on line 20 itself indicates that control flow might be diverted like this. Exception handling introduces precisely this kind of hidden control flow possibility, at nearly every significant line of code: every function/method call, every new object construction, every overloaded operator etc.

      核心問題是隱藏的控制流可能性. 有一個著名的笑話, 講的是一種神秘的編程語言結構, 叫做 comefrom, 他模仿了許多早期編程語言中存在問題的goto語句. 這個想法是, 程序員可以在程序中的任何時候說"comefrom 20", 任何時候執行到第 20 行, 他都會立即跳轉到"comefrom"代碼. 這里要指出的是, 第 20 行本身沒有任何東西 表明控制流可能會像這樣轉向. 異常處理正是在幾乎每一行代碼中引入了這種隱藏的控制流可能性: 每一個函數/方法調用, 每一個新對象構造, 每一個重載操作符等等

      Exception handling thus breaks the "principle of least astonishment", and breaks it HUGE.

      因此, 異常處理打破了"最小驚訝原則", 并將其打爆.

      Joel Spolsky expresses the issue in his concise and down-to-earth manner as follows: "They are invisible in the source code. Looking at a block of code, including functions which may or may not throw exceptions, there is no way to see which exceptions might be thrown and from where. This means that even careful code inspection doesn't reveal potential bugs. ... To write correct code, you really have to think about every possible code path through your function. Every time you call a function that can raise an exception and don't catch it on the spot, you create opportunities for surprise bugs caused by functions that terminated abruptly, leaving data in an inconsistent state, or other code paths that you didn't think about."

      Joel Spolsky 他以簡潔和踏實的方式表達了以下問題: "他們在源代碼中是不可見的. 查看一段代碼, 包括可能引發或可能不會引發異常的函數, 無法查看可能會引發哪些異常以及從何處引發. 這意味著, 即使是仔細的代碼檢查也不會發現潛在的錯誤. ... 要編寫正確的代碼, 必須考慮通過函數的所有可能的代碼路徑. 每次調用一個可能引發異常但未當場捕獲的函數時, 都會產生意外的錯誤, 這些錯誤是由突然終止的函數引起的, 導致數據處于不一致的狀態, 或者是您沒有想到的其他代碼路徑."

      Mismatch With Parallel Programming

      與并行編程不匹配

      The very idea of rollback/unwinding which is so central to exception handling more-or-less inherently implies that there is a sequential call chain to unwind, or some other way to "go back" through the callers to find the nearest enclosing catch block. This is horribly at odds with any model of parallel programming, which makes exception handling very much less than ideal going forward into the many-core, parallel programming era which is the future of computing.

      回滾(rollback)/回溯(unwinding) 對異常處理來說是如此核心, 這一點本身就意味著有一個順序調用鏈需要回溯, 或者通過其他方式"返回"調用方以找到最近的封閉 catch 塊. 這與任何并行編程模型都極為不一致, 這使得異常處理在進入多核并行編程時代(這是計算機的未來)變得非常不理想

      Even when considering the simplest possible parallel programming model of all – a straightforward parallel fork/join, such as processing all of the elements of an array in parallel – the problem is immediately obvious. What should you do if you fork 20 threads and just one of them throws an exception? Unwind back past the forking and kill the other 19 threads, risking data corruption? Unwind but leave the other 19 threads running never to be joined/reaped, and doing who knows what to objects you supposedly destroyed during the unwinding? Make the programmer put in a catch block at the point of forking, which still has to choose between those two basic possibilities anyway?

      即使考慮到最簡單的并行編程模型 – 簡單的并行 fork/join, 比如并行處理數組的所有元素 – 問題也顯而易見. 如果 fork 20 個線程, 其中只有一個拋出異常, 該怎么辦? 把之前回收回去嗎, 殺死其他 19 個線程, 冒著數據損壞的風險? 繼續, 但讓其他 19 個線程運行, 永遠不會被連接(joined)/獲取(reaped), 誰知道在繼續過程中你應該回溯什么對象? 讓程序員在 forking 時放入一個 catch 塊, 無論如何, 他仍然必須在這兩種基本可能情況之間進行選擇

      Moving to more interesting and useful models of parallelism, exception handling again seems completely mismatched. Today, for example, the most common practical model used for flexible parallelism is a pool of worker threads each executing small units of work, often called tasks or operations, which are stored in some kind of work queue and dispatched to the thread pool one after another as each thread finishes its current task. Applying exception handling to such a scheme seems impossible, since the units of work are essentially detached from any "caller". The whole concept of unwinding the call stack makes no sense at all in such a situation.

      轉到更有趣, 更有用的并行模型, 異常處理似乎再次完全不搭. 例如, 今天, 用于靈活并行的最常見的實用模型是一個工作線程池, 每個工作線程執行小的工作單元, 通常稱為任務或操作, 他們存儲在某種工作隊列中, 并在每個線程完成其當前任務時一個接一個地分派到線程池. 對這樣的方案應用異常處理似乎是不可能的, 因為工作單元基本上與任何"調用方"分離(detached). 在這種情況下, 回溯調用堆棧的整個概念毫無意義

      More sophisticated parallel programming models, such as asynchronous message passing between communicating sequential processes (CSP or the "actor" model), have similar properties to the thread pool and task queue approach, though these properties are hidden by proper language support. Again, since there is no obvious execution path to unwind, and since messages between objects/actors are frequently asynchronous, it is difficult to see how the general approach of exception handling can be applied.

      更復雜的并行編程模型, 如通信順序進程(CSP 或"actor(參與者)"模型)之間的異步消息傳遞, 具有與線程池和任務隊列方法類似的屬性, 盡管這些屬性通過適當的語言標準支持. 同樣, 由于沒有明顯的執行路徑來展開, 而且對象/參與者之間的消息通常是異步的, 因此很難看到如何應用異常處理的一般方法

      Finally, because exceptions are an out-of-band control mechanism, existing outside the normal call/return mechanism, they don't fit very well when the CSP or actor model is taken to its logical next step, with objects/actors on different systems connected by a network. You can easily return an error code over a byte stream that happens to be a network connection, but you can't easily throw an exception back over a network connection, because the exception is "out of band" – it doesn't come back via the normal data channel. An elaborate runtime system could, of course, work around this, but is that really a sensible approach?

      最后, 由于異常是一種帶外控制機制, 存在于正常的 調用(call)/返回(return) 機制之外, 因此當 CSP 或 actor 參與者模型 進入其邏輯下一步時, 他們不太適合, 不同系統上的對象/參與者通過網絡連接. 您可以通過恰好是網絡連接的字節流輕松地返回錯誤代碼, 但不能通過網絡連接輕松地拋出異常, 因為異常是"帶外"的 – 他不會通過正常的數據通道返回. 一個精心設計的運行時系統當然可以解決這個問題, 但這真的是一種明智的方法嗎?

      The simple fact is the concept of rollback/unwinding just doesn't work very well in a highly parallel situation, even a simple one like fork/join, let alone more sophisticated and useful models like thread pools or CSP/actors. Trying to retrofit exceptions and rollback/unwinding into a parallel environment seems like an exercise in complexity, frustration and ultimately futility.

      簡單的事實是, 回滾/回溯的概念在高度并行的情況下無法很好地工作, 即使是像 fork/join 這樣的簡單情況, 更不用說像線程池或 CSP/actors 這樣更復雜, 更有用的模型了. 試圖改造異常并回滾/回溯到并行環境似乎是一種復雜, 最終徒勞的沮喪練習

      Exceptional Exceptions

      特殊 Exceptions

      Many advocates of exception handling admit that it is best used only for extremely rare "exceptional" cases. In other words, you should use error return codes for anything that might actually happen in real life, but as long as you only use exceptions for things that will never actually happen they're fine. Maybe I'm exaggerating for effect here, but you get the point.

      許多異常處理的倡導者承認, 他最好只用于極為罕見的"異常"情況. 換句話說, 你應該對現實生活中可能發生的任何事情使用錯誤返回碼, 但只要你只對永遠不會發生的事情使用異常, 他們就可以了. 也許我夸大了這里的效果, 但你明白了

      I personally take the view that most of the "exceptional" cases they're talking about should basically just be guaranteed by the system to never happen at all – memory allocation failures, runtime stack exhaustion, other kinds of resource exhaustion, memory access violations etc. We shouldn't be exposing those kinds of things to applications at all, because in nearly all cases there is precious little the application can sensibly do to recover from the error anyway. There's useful complexity and then there's useless complexity, and having to write application code to deal with things that will never really happen, or for which the only safe response is program termination anyway, is just adding useless complexity.

      我個人認為, 他們所說的大多數"例外"情況基本上應該由系統保證永遠不會發生——內存分配失敗, 運行時堆棧耗盡, 其他類型的資源耗盡, 內存訪問違規等. 我們根本不應該向應用程序公開這些情況,因為幾乎在所有情況下, 應用程序都無法明智地從錯誤中恢復. 有有用的復雜性, 也有無用的復雜性, 而必須編寫應用程序代碼來處理永遠不會真正發生的事情, 或是唯一安全的響應是程序終止, 這只會增加無用的復雜性

      Instead, we should be presenting applications with the illusion of a machine with infinite resources, thereby making writing applications that much simpler and less error-prone. If physical resources actually do become exhausted, it should be the responsibility of the operating system, not the application, to take appropriate action. As a simple example, memory allocation should be guaranteed not to fail in general, with special options to return NULL on failure for those few rare cases where recovery from failure makes sense (such as allocating a very large image or handling the possibility of failure in some alternative way like working at a lower resolution).

      相反, 我們應該讓應用程序看起來像一臺擁有無限資源的機器, 從而使編寫應用程序變得更簡單, 更不容易出錯. 如果物理資源確實耗盡, 那么采取適當的措施應該是操作系統的責任, 而不是應用程序的責任. 舉個簡單的例子, 應該保證內存分配通常不會失敗, 對于少數幾種罕見的情況, 如果從失敗中恢復是有意義的(例如分配一個非常大的圖像, 或者以某種替代方式處理失敗的可能性, 比如以較低的分辨率工作), 可以使用特殊選項在失敗時返回 NULL

      For those of you who say "but what about small, embedded devices that have real resource limits?", the answer there is simply to go and look at what's actually being done in the embedded space today. We already have small embedded devices which function as wireless network hotspots, print servers, music servers and NAS servers, all at the same time, all in the size of a power brick. The notion of having "special" versions of programs which run in embedded space and which constantly have to handle resource limits is just as dead as the idea of "special" content for mobile devices (can anyone remember WAP or i-Mode?).

      對于那些說"但是小型嵌入式設備有真正的資源限制怎么辦?"的人來說, 答案就是去看看今天在嵌入式空間中實際做了什么. 我們已經有了小型嵌入式設備, 他們可以同時充當無線網絡熱點, 打印服務器, 音樂服務器和 NAS 服務器, 所有這些設備都有一塊電源磚那么大. 讓"特殊"版本的程序在嵌入式空間中運行并不斷處理資源限制的想法, 與為移動設備提供"特殊"內容的想法(有人記得 WAP 或 i-Mode 嗎?) 一樣已經過時

      The future is essentially standard, general-purpose applications, maybe slightly cut down, running on top of slightly cut down but essentially standard, full-blown OSs, all on your phone, or your watch, or inside your soap dispenser. It's a world where even your toaster runs Linux. In such a world, exposing resource limits like the remote possibility of memory allocation failure to applications is just silly.

      未來基本上是標準的, 通用的應用程序, 可能會稍微減少, 運行在稍微減少但基本上是標準的, 全面的操作系統之上, 所有這些都在你的手機, 手表或皂液器(soap dispenser)中. 這是一個連你的烤面包機都運行 Linux 的世界. 在這樣一個世界里, 向應用程序公開資源限制, 比如內存分配失敗的可能性是非常愚蠢的.

      Finally

      最后

      The cold, hard truth is that if you exclude trivial use of exceptions where the exception is caught and handled immediately, essentially mimicking the old error return code approach, then 90% of the other exception handling code out there in the wild isn't exception-safe. It works just fine, as long as an exception never actually happens, but if one does you're basically hosed. Or, to quote Michael Grier: "Exceptions only really work reliably when nobody catches them."

      冷酷而殘酷的事實是, 如果你排除了異常被立即捕獲和處理的瑣碎使用, 基本上模仿了舊的返回錯誤碼方法, 那么在其他狂亂異常處理代碼中, 90% 都不是異常安全的. 只要異常從未真正發生過, 他就可以正常工作, 但如果發生了, 你基本上是被水淹沒了. 或者, 引用Michael Grier: "只有在沒有人發現異常時, 異常才會真正可靠地工作."

      I believe this clearly tells you there is a problem with the language feature, and the very idea IMHO. I am certain 99% of C++ code isn't exception-safe, I'm equally sure 99% of Objective-C code isn't exception-safe, and I'd be willing to bet a good 90% of Java code isn't exception-safe either, even with garbage collection to clean up memory leaks. The problem isn't just memory leaks, or even unclosed files and network sockets, it's modifications to shared data structures (and related equivalents like database state, partially written files etc). Those don't get undone by unwinding the stack and destroying local objects, nor by a garbage collector, no matter how smart it is about trying to call finalize() methods in the right order.

      我相信這清楚地告訴你, 語言功能和思想本身存在問題. 我確信 C++ 代碼中的 99% 不是異常安全(exception-safe), 我同樣確信 99% 的 Objective-C 代碼也不是異常安全的, 而且我愿意打賭, 即使是垃圾收集來清理內存泄漏, 也有 90% 的 java 代碼也不例外. 問題不僅僅在于內存泄漏, 甚至包括未關閉的文件和網絡套接字, 還在于對共享數據結構(以及數據庫狀態, 部分寫入的文件等相關等價物)的修改這些不會通過展開堆棧和銷毀本地對象來撤消, 也不會通過垃圾收集器來撤消, 無論他嘗試以正確的順序調用finalize()方法有多聰明.

      I vote that all programming language designers should just say no to exceptions. I know I do.

      我認為所有編程語言設計師都應該拒絕異常. 我懂我才用

      Exception handling doesn't really work. It doesn't give the benefits it claims. Hardly any real-world code uses it correctly except in the trivial case, which is just a more verbose equivalent of error return codes. Nobody really uses exceptions to any genuine benefit. They just get in the way and make writing code more silently error-prone. And exception handling is a horrible, horrible mismatch to highly parallel programming.

      異常處理實際上不起作用. 他沒有提供他聲稱的好處. 幾乎沒有任何真實世界的代碼正確地使用它, 除了在瑣碎的情況下, 這只是一個更詳細的錯誤返回代碼等價物. 沒有人真正利用異常來獲得任何真正的好處. 他們只是礙事, 讓編寫代碼更容易出錯. 異常處理與高度并行編程是一種可怕的, 可怕的完全不搭

      Error return codes work. They are simple. They are effective. They have stood the test of time. More to the point, they are what everyone actually uses when they know an error might really actually happen! That tells you a LOT.

      錯誤返回代碼有用. 他們很簡單. 他們是高效的. 他們經受住了時間的考驗. 更重要的是, 當每個人知道錯誤可能真的會發生時, 他們都會使用他們! 這會告訴你非常多重要S信息.

      If you're a programming language designer, I encourage you to just say no to exceptions, and take your first step into a better, more reliable world.

      如果你是一名編程語言設計師, 我鼓勵你對異常說, 然后邁出第一步, 進入一個更好, 更可靠的世界.

       

       

      posted on 2022-04-02 12:59  喜ω歡  閱讀(202)  評論(2)    收藏  舉報

      主站蜘蛛池模板: 久青草国产在视频在线观看| 狠狠cao日日穞夜夜穞av| 国产精品午夜精品福利| 欧美一区二区三区激情| 国产av一区二区三区精品| 操操操综合网| 通化市| 国产suv精品一区二区五| 国产三级国产精品久久成人| 在线观看热码亚洲AV每日更新| 无码少妇一区二区三区免费| AV教师一区高清| 国产一国产看免费高清片| 欧美亚洲综合成人A∨在线| 亚洲夂夂婷婷色拍ww47| 国产精品呻吟一区二区三区| 69天堂人成无码免费视频| 光棍天堂在线手机播放免费| 制服 丝袜 亚洲 中文 综合| 一本色道国产在线观看二区| 国产成人一区二区三区免费| 经典国产乱子伦精品视频| 久久se精品一区精品二区国产| 国产精品黄色大片在线看| 在线视频中文字幕二区| 亚洲午夜无码久久久久蜜臀av | 午夜爽爽爽男女污污污网站| 中文人妻av高清一区二区| 99在线小视频| 国产99久久亚洲综合精品西瓜tv| 色综合五月伊人六月丁香| 亚洲另类激情专区小说图片 | 内射中出无码护士在线| 艳妇乳肉豪妇荡乳xxx| 国99久9在线 | 免费| 国产性三级高清在线观看| 亚洲最大成人免费av| 97超级碰碰碰碰久久久久| 99久久er这里只有精品18| 国产中文一区卡二区不卡| 日韩AV高清在线看片|