예외처리(프로그래밍)

Exception handling (programming)

컴퓨터 프로그래밍에는 예외 처리를 위한가지 언어 메커니즘이 존재합니다.예외라는 용어는 일반적으로 예외 상태에 대한 정보를 저장하는 데이터 구조를 나타내는 데 사용됩니다.제어권을 이전하거나 예외를 제기하는 하나의 메커니즘을 스로라고 하는데, 예외는 스로라고 합니다.실행은 캐치에 옮겨집니다.

프로그래밍 언어는 예외가 무엇인지에 대한 개념이 상당히 다릅니다.현대의 언어는 크게 두 그룹으로 [1][note 1]나눌 수 있습니다.

  • 예외가 흐름 제어 구조로 사용되도록 설계된 언어:Ada, Modula-3, ML, OCaml, PL/I, Python, Ruby 등이 이 범주에 속합니다.예를 들어 Python의 반복자는 반복자[2]더 이상 생성하지 않는 항목을 표시하기 위해 반복 중지 예외를 던집니다.
  • 예외가 비정상적이고 예측 불가능하며 오류가 있는 상황을 처리하는 데만 사용되는 언어:C++,[3] Java,[4] C#, Common Lisp, Eiffel 및 Modula-2.

역사

1960년대와 1970년대에 개발된 소프트웨어 예외 처리.LISP 1.5 (1958-1961)[5]는 예외를 제기할 수 있도록 허용했습니다.ERROR해석기나 컴파일러에 의해 제기된 오류와 유사한 의사 함수.예외는 다음과 같습니다.ERRORSET키워드, 반환된NIL 프로그램을 종료하거나 [6]디버거를 입력하는 대신 오류가 발생한 경우.PL/I는 1964년경에 자체적인 형태의 예외 처리를 도입하여 인터럽트를 ON [7]장치로 처리할 수 있게 했습니다.맥리스프는 다음과 같이 관찰했습니다.ERRSET그리고.ERR오류 발생뿐만 아니라 non-local control flow를 위해 사용되었으며, 따라서 두 개의 새로운 키워드를 추가했습니다.CATCH그리고.THROW([8]1972년 6월).현재 일반적으로 "finally"라고 불리는 정화 행동은 1970년대 중후반 NIL(New Implementation of LISP)에서 도입되었습니다.UNWIND-PROTECT.[9][9] 후 커먼 리스프가 이를 채택했습니다.이것과 동시대의 것은dynamic-wind폐쇄에서 예외를 처리했던 스킴(Scheme).구조적 예외 처리에 관한 최초의 논문은 Goodenough(1975a)Goodenough(1975b)[10]였습니다.예외 처리는 이후 1980년대부터 많은 프로그래밍 언어에서 널리 채택되었습니다.

구문

많은 컴퓨터 언어에는 예외 및 예외 처리를 위한 구문 지원이 내장되어 있습니다.여기에는 액션스크립트, Ada, BlitzMax, C++, C#, Clojure, COBOL, D, ECMAscript, 에펠, 자바, ML, 오브젝트 파스칼(: 델파이, 프리 파스칼 등), 파워빌더, 오브젝티브-C, OCaml, PHP(버전 5 기준), PL/I, PL/SQL, Prolog, Python, REALbasic, Ruby, Scala, Seed7, Smalltalk, Tcl, Visual Prolog 등이 포함됩니다.NET 언어.

사소한 구문 차이를 제외하고 사용 중인 예외 처리 스타일은 몇 가지뿐입니다.가장 일반적인 스타일에서 예외는 특별한 문장으로 시작됩니다 (throw아니면raise예외 개체(예: Java 또는 Object Pascal) 또는 특별한 확장 가능한 열거형 값(예: Ada 또는 SML)이 있는 경우.예외 처리기의 범위는 마커 절로 시작합니다(try또는 언어의 블록을 시작할 때, 예를 들어 다음과 같은begin) 및 첫번째 핸들러 조항의 시작 부분에서 끝납니다(catch,except,rescue몇 개의 핸들러 절이 뒤를 이을 수 있으며, 각 절은 어떤 예외 유형을 처리하고 예외 개체에 어떤 이름을 사용하는지 지정할 수 있습니다.약간의 변형으로 일부 언어는 단일 핸들러 절을 사용하는데, 이 절은 내부적으로 예외의 클래스를 다룹니다.

관련 조항도 공통입니다(finally아니면ensure예외 처리 블록의 본문 내에서 획득한 리소스를 해제하기 위해 일반적으로 예외가 발생했는지 여부에 관계없이 실행됩니다.특히 C++는 이러한 구성 요소를 제공하지 않으며 대신 디스트럭터를 [11]사용하여 리소스를 해방하는 RAI(Resource Acquisition Is Initialization) 기법을 권장합니다.Westley Weimer와 George Neucla의 2008년 논문에 따르면, 의 구문.try...finally자바의 블록은 소프트웨어 결함의 원인이 됩니다.한 방법이 3-5개의 자원의 획득과 방출을 처리해야 할 때, 프로그래머들은 이것이 올바른 해결책이 되더라도 가독성 문제 때문에 충분한 블록을 둥지로 옮기는 것을 꺼리는 것이 분명합니다.싱글을 사용할 수 있습니다.try...finally블록은 여러 리소스를 처리할 때에도 차단되지만, 이는 보초 값의 정확한 사용을 요구하며, 이는 이러한 [12]: 8:6–8:7 유형의 문제에 대한 또 다른 일반적인 버그 소스입니다.

Python과 Ruby도 조항을 허용합니다.else처리기 범위가 종료되기 전에 예외가 발생하지 않은 경우에 사용됩니다.

전체적으로 예외 처리 코드는 다음과 같이 보일 수 있습니다(Java 유사 의사 코드에서).

해라 {      = 위로의.읽기 줄();      한다면 (.길이() == 0) {         던지다 신규 빈 줄 예외("콘솔에서 읽은 줄이 비어 있었습니다!");     }      위로의.프린트라인("안녕 %s!" % ); } 또 만나 (빈 줄 예외 e) {     위로의.프린트라인("안녕하세요!"); } 또 만나 (예외. e) {     위로의.프린트라인("오류: " + e.메세지()); } 또 다른 {     위로의.프린트라인("프로그램이 성공적으로 실행되었습니다."); } 마침내. {     위로의.프린트라인("프로그램이 이제 종료됩니다."); } 

C는 Try-catch 예외 처리 기능이 없지만 오류 검사를 위해 반환 코드를 사용합니다.및 표준 라이브러리 기능setjmp [13]사용하여 매크로를 통한 트라이캐치 처리를 구현할 수 있습니다.

Perl 5 사용die위해서throw그리고.eval {} if ($@) {}시음용으로트라이캐치 [14]시맨틱스를 제공하는 CPAN 모듈이 있습니다.

종료 및 재개 의미론

예외가 던져지면 프로그램은 예외 처리기가 발견될 때까지 함수 호출 스택을 통해 다시 검색합니다.일부 언어에서는 이 검색이 진행될 때 스택을 해제해야 합니다.즉, if 함수f, 예외 E에 대한 핸들러 H를 포함하고, 함수 g를 호출하고, 함수 h를 호출하고, 예외 E가 h에서 발생하면, 함수 h 및 g는 종료될 수 있고, 힌f는 E를 처리입니다.이것은 종료 의미론이라고 합니다.또는 예외 처리 메커니즘은 예외 처리기에 진입할[note 2] 때 스택을 풀지 않을 수 있으며, 예외 처리기에 계산을 다시 시작하거나, 다시 시작하거나, 풀 수 있는 옵션을 제공합니다.이를 통해 프로그램은 오류가 발생한 위치와 정확히 동일한 위치에서 계산을 계속하거나(예: 이전에 누락된 파일을 사용할 수 있게 된 경우) 예외 처리 메커니즘 위에 알림, 로깅, 쿼리 및 유체 변수를 구현할 수 있습니다(Smalltalk에서 수행된 것처럼).계산이 중단된 곳에서 재개되도록 허용하는 것을 재개 의미론이라고 합니다.

두 가지 결정 중 하나에 찬성하는 이론적 주장과 설계적 주장이 있습니다.1989-1991년의 C++ 표준화 논의는 C++[15]에서 종결 의미론을 사용하기로 최종 결정하는 결과를 낳았습니다.Bjarne StrostrupJim Mitchell의 프레젠테이션을 주요 데이터 포인트로 꼽고 있습니다.

Jim은 20년 동안 6개 언어의 예외 처리를 사용했으며, Xerox의 Cedar/Mesa 시스템의 주요 설계자 및 구현자 중 한 명으로서 재개 의미론을 초기에 지지했습니다.그의 메세지는

"재개보다는 종료를 선호합니다. 이것은 의견의 문제가 아니라 수년간의 경험의 문제입니다.재개는 유혹적이지만 타당하지 않습니다."

그는 여러 운영 체제의 경험을 바탕으로 이 진술을 뒷받침했습니다.주요 사례는 Cedar/Mesa였습니다.재개를 좋아하고 사용하는 사람들에 의해 작성되었지만, 10년간 사용된 후에, 50만 회선 시스템에서 재개의 사용은 단 한 번밖에 남지 않았고, 그것은 문맥에 의한 문의였습니다.그러한 상황 조사에 있어서 재개가 실제로 필요하지 않았기 때문에, 그들은 그것을 제거했고 시스템의 그 부분에서 상당한 속도 증가를 발견했습니다.재개가 사용된 모든 경우에 10년에 걸쳐 문제가 되었고 보다 적합한 설계가 재개되었습니다.기본적으로, 재개의 모든 사용은 추상화의 분리 [10]수준을 유지하는 데 실패했음을 나타냅니다.

재개되는 예외 처리 언어로는 Common Lisp with the Condition System, PL/I, Dylan, R,[16] Smalltalk 등이 있습니다.그러나 대부분의 새로운 프로그래밍 언어는 C++를 따르고 종료 시맨틱을 사용합니다.

예외처리구현

프로그래밍 언어에서 예외 처리의 구현은 일반적으로 코드 생성기와 컴파일러를 수반하는 런타임 시스템의 상당한 지원을 포함합니다. (원래 C++ 컴파일러[17]Cfront의 유효 수명을 끝낸 것은 C++에 예외 처리를 추가한 것입니다.)두 가지 계획이 가장 일반적입니다.첫 번째 동적 등록은 예외 [18]처리 측면에서 프로그램 상태에 대한 구조를 지속적으로 업데이트하는 코드를 생성합니다.일반적으로 스택 프레임 레이아웃에 해당 프레임과 관련된 함수 또는 메서드에 사용할 수 있는 핸들러를 파악하는 새 요소가 추가됩니다. 예외가 발생하면 레이아웃의 포인터가 해당 핸들러 코드로 런타임을 지시합니다.이 접근 방식은 공간적인 측면에서 콤팩트하지만, 프레임 진입과 퇴출에 실행 오버헤드가 추가됩니다.예를 들어, 이미 많은 다른 언어 기능에 대해 복잡한 생성 및 런타임 지원이 필요했던 많은 Ada 구현에서 일반적으로 사용되었습니다.마이크로소프트의 32비트 구조 예외 처리(SEH)는 이 방법을 별도의 예외 [19]스택과 함께 사용합니다.동적 등록은 정의하기에 매우 간단하며,[20] 정확성을 증명할 수 있습니다.

두 번째 계획은 많은 생산 품질의 C++ 컴파일러와 64비트 마이크로소프트 SEH에 구현된 것으로 테이블 기반 접근 방식입니다.이것은 컴파일 시간과 링크 시간에 예외 처리와 관련하여 프로그램 [21]카운터의 범위를 프로그램 상태와 연관시키는 정적 테이블을 만듭니다.그런 다음 예외가 발생하면 런타임 시스템은 테이블에서 현재 명령어 위치를 찾아 재생 중인 핸들러와 수행해야 할 작업을 결정합니다.이 접근 방식은 예외가 적용되지 않는 경우에 대한 경영진의 오버헤드를 최소화합니다.이는 일부 공간의 비용으로 발생하지만, 이 공간은 읽기 전용 특수 목적 데이터 섹션에 할당될 수 있으며, 이 섹션은 예외가 실제로 [22]적용될 때까지 로드되거나 재배치되지 않습니다.예외를 처리하기 위한 코드의 위치(메모리 내)는 함수의 코드의 나머지 부분이 저장되는 메모리 영역 내(또는 근처)에 위치할 필요가 없습니다.따라서 예외가 발생할 경우 필요한 예외 처리 코드를 로드/캐시해야 하는 경우 함수[23] 호출과 유사한 성능 히트가 발생할 수 있습니다.그러나 이 방식은 예외가 없는 경우 성능 비용이 최소화됩니다.C++의 예외는 예외적인(즉, 흔하지 않은/흔하지 않은) 사건으로 간주되기 때문에, C++의 예외 처리를 설명하는 데 "제로 비용 예외"[note 3]라는 문구가 사용되기도 합니다.런타임 유형 식별(RTTI)과 마찬가지로 예외 처리는 룩업 테이블에 대해 [24]0이 아닌 양의 메모리가 필요하므로 예외는 C++의 제로 오버헤드 원칙을 준수하지 않을 수 있습니다.이러한 이유로 많은 C++ 컴파일러에서 예외 처리(및 RTTI)를 사용하지 않도록 설정할 수 있으며, 이는 메모리가[24] 매우 제한된 시스템(: 임베디드 시스템)에 유용할 수 있습니다.이 두 번째 접근 방식은 스레드[citation needed] 안전성을 달성하는 면에서도 우수합니다.

다른 정의 및 구현 방안도 제안되었습니다.메타프로그래밍을 지원하는 언어의 경우 오버헤드가 전혀 수반되지 않는 접근법이 [25](이미 존재하는 반사 지원을 넘어) 발전했습니다.

계약에 의한 설계에 의한 예외처리

예외에 대한 다른 관점은 계약에 의한 설계 원칙에 기초하고 있으며 특히 에펠탑 언어에 의해 지지되고 있습니다.이 아이디어는 "정상" 및 "비정상" 행동이 무엇인지 정확하게 정의함으로써 예외 처리에 대한 보다 엄격한 근거를 제공하는 것입니다.구체적으로 접근 방식은 두 가지 개념을 기반으로 합니다.

  • 실패: 계약을 이행할 수 없는 작업.예를 들어, 덧셈은 산술 오버플로(수학적 합에 대한 좋은 근사치 계산 계약을 이행하지 않음)를 발생시키거나 루틴이 사후 조건을 충족하지 못할 수 있습니다.
  • 예외: 루틴을 실행하는 동안 발생하는 비정상적인 이벤트(해당 루틴이 예외의 "수신자"임).이러한 비정상적인 이벤트는 루틴에 의해 호출된 작업의 실패로 인해 발생합니다.

Bertrand Meyer가 Object-Oriented Software Construction에서 소개한 "Safe Exception Handling 원칙"에 따르면 예외가 발생했을 때 루틴이 반응할 수 있는 의미 있는 방법은 두 가지뿐이라고 합니다.

  • 실패 또는 "조직적 공황":루틴은 불변성을 다시 설정하여 개체의 상태를 수정한 다음(이것이 "조직된" 부분임) 실패하여(패닉) 호출자에서 예외를 트리거합니다(비정상 이벤트가 무시되지 않도록).
  • 재시도(Retry): 루틴은 일반적으로 일부 값을 변경한 후 알고리즘을 다시 시도하여 다음 시도가 성공할 가능성이 커집니다.

특히, 단순히 예외를 무시하는 것은 허용되지 않으며, 블록을 다시 시도하여 성공적으로 완료하거나 예외를 호출자에게 전파해야 합니다.

여기 에펠 구문으로 표현된 예가 있습니다.일상적인 일이send_fast보통은 메시지를 보내는 것이 더 나은 방법이지만 실패하여 예외가 발생할 수 있습니다. 만약 그렇다면 알고리즘은 다음을 사용합니다.send_slow, 자주 실패하지 않을 겁니다 만약에send_slow실패, 루틴send전체적으로 실패해서 발신자가 예외를 받게 됩니다.

보내세요 (m: 메세지)    -- 가능하면 빠른 링크를 통해, 그렇지 않으면 느린 링크를 통해 m을 보냅니다. 현지의   시도된_빠름, 노력한_느린: 부울 하다   한다면 시도된_빠름 그리고나서      노력한_느린 := 진실의      send_slow (m)   또 다른      시도된_빠름 := 진실의      빨리 보내다 (m)   끝. 구조.   한다면 것은 아니다. 노력한_느린 그리고나서      재시도   끝. 끝. 

부울 로컬 변수는 시작할 때 False로 초기화됩니다. 만약send_fast실패, 본문(do조항)을 다시 실행하여 의 실행을 야기할 것입니다.send_slow. 만약 이 실행이send_slow실패하다, 더rescue절은 끝까지 실행됩니다.retry(아니오)else결승전의 조항if), 전체적으로 일상적인 실행이 실패하게 합니다.

이 접근법은 "정상적인" 경우와 "비정상적인" 경우가 무엇인지 명확하게 정의할 수 있는 장점이 있습니다: 예외를 야기하는 비정상적인 경우는 일상이 계약을 이행할 수 없는 경우입니다.역할의 명확한 분배를 정의합니다.do조항(정상적인 기관)은 루틴의 계약을 달성하거나 달성하려고 시도하는 것을 담당합니다.rescue절은 성공할 가능성이 있지만 실제 계산을 수행하지 않는 경우 컨텍스트를 다시 설정하고 프로세스를 다시 시작하는 역할을 담당합니다.

에펠의 예외는 꽤 명확한 철학을 가지고 있지만, Kiniry(2006)는 "언어 정의의 일부인 예외는 INTEGER 값으로, 개발자 정의 예외는 STRING 값으로 표시됩니다. [...] 또한, 객체가 아닌 기본 값이기 때문에 고유한 의미론을 갖지 않습니다.그 이상은 효과적인 표현 과부하로 인해 반드시 오류를 범할 수 없는 도우미 루틴으로 표현됩니다(예: 동일한 값의 두 정수를 구별할 수 없음)."[1]

탐지되지 않은 예외

현대의 응용 프로그램들은 예외 처리 전략을 고려할 때 많은 설계 과제에 직면합니다.특히 현대의 엔터프라이즈급 애플리케이션에서는 예외가 프로세스 경계와 기계 경계를 넘나들어야 하는 경우가 많습니다.견고한 예외 처리 전략 설계의 일부는 [26]프로세스의 소프트웨어 부분이 경제적으로 처리할 수 없을 정도로 프로세스가 실패했을 때 인식하는 것입니다.

예외가 던져지고 잡히지 않으면(작동적으로, 예외는 지정된 해당 핸들러가 없을 때 던져짐), 포착되지 않은 예외는 런타임에 의해 처리됩니다. 이렇게 하는 루틴을 포착되지 않은 예외 [27][28]핸들러라고 합니다.가장 일반적인 기본 동작은 프로그램을 종료하고 콘솔에 오류 메시지를 인쇄하는 것으로, 일반적으로 예외의 문자열 표현 [27][29][30]스택 추적과 같은 디버그 정보를 포함합니다.런타임에 도달하기 전에 예외를 포착하는 최상위(예:[27][31] 이벤트 루프) 처리기를 사용하면 이러한 문제가 해결되는 경우가 많습니다.

예외가 포착되지 않으면 프로그램이 비정상적으로 종료될 수 있지만(예외가 포착되지 않으면, 특히 부분적으로 완료된 트랜잭션을 롤백하지 않거나 리소스를 해제하지 않음으로써 프로그램이 정확하지 않을 수 있음), 프로세스는 정상적으로 종료됩니다.런타임(프로그램의 실행을 제어하는)은 프로세스의 정상적인 종료를 보장할 수 있기 때문입니다.

다중 스레드 프로그램에서 스레드에서 포착되지 않은 예외는 대신 전체 프로세스가 아닌 해당 스레드만 종료할 수 있습니다(스레드 레벨 핸들러에서 포착되지 않은 예외는 최상위 핸들러에 의해 포착됨).예를 들어 서버에 전체적인 영향을 주지 않고 서블릿(자체 스레드에서 실행)을 종료할 수 있는 서버에서 특히 중요합니다.

이 기본 탐지되지 않은 예외 처리기는 예를 들어 탐지되지 않은 예외에 대한 대체 로깅 또는 최종 사용자 보고를 제공하거나 탐지되지 않은 예외로 인해 종료되는 스레드를 재시작하기 위해 전역 또는 스레드 단위로 재정의될 수 있습니다.예를 들어 자바에서는 다음을 통해 단일 스레드에 대해 수행됩니다.Thread.setUncaughtExceptionHandler를 통해 전세계적으로Thread.setDefaultUncaughtExceptionHandler; 파이썬에서 이것은 수정함으로써 이루어집니다.sys.excepthook.

확인된 예외 사항

자바는 특별한 종류의 예외인 확인된 [32][33]예외의 개념을 도입했습니다.메서드에서 발생할 수 있는 확인된 예외는 메서드의 서명에 포함되어야 합니다.예를 들어, 만약 어떤 방법이IOException, 메소드 서명에 이 사실을 명시적으로 선언해야 합니다.그렇지 않으면 컴파일 시간 오류가 발생합니다.Hanspeter Mössenböck에 따르면, 확인된 예외는 덜 편리하지만 더 [34]강력합니다.선택한 예외는 컴파일특정 응용프로그램의 런타임에 처리되지 않은 예외의 발생률을 줄일 수 있습니다.

키니리(Kiniry)는 "자바 프로그래머들이 알고 있듯이,try catch 일반적인 Java 애플리케이션의 코드는 예외를 확인하지 않은 다른 언어에서 명시적인 형식 매개 변수와 반환 값 확인에 필요한 비교 가능한 코드보다 큰 경우가 있습니다.사실, 확인된 예외를 처리하는 것은 문서를 작성하는 것만큼이나 불쾌한 일이라는 것이 대세 자바 프로그래머들의 대체적인 공감대입니다.따라서 많은 프로그래머들이 확인된 [1]예외를 "재전송"한다고 보고합니다.마틴 파울러(Martin Fowler)는 "...대체로 예외는 좋다고 생각하지만 자바가 확인한 예외는 가치 [35]있는 것보다 더 문제가 됩니다."라고 썼습니다.2006년 현재 확인된 [35]예외를 추가하는 데 있어 자바를 따르는 주요 프로그래밍 언어는 없습니다.예를 들어, C#은 Eric [36][1][35]Gunnerson이 게시한 다음과 같은 예외 사양을 선언할 필요가 없거나 허용하지 않습니다.

"소규모 프로그램을 검토하면 예외 사양을 요구하면 개발자 생산성을 향상시키고 코드 품질을 향상시킬 수 있다는 결론이 도출되지만, 대규모 소프트웨어 프로젝트의 경험은 생산성 저하와 코드 품질 향상이라는 다른 결과를 제시합니다."

Anders Hejlsberg는 확인된 [37]예외와 관련하여 두 가지 문제를 설명합니다.

  • Versioning: 예외 X 및 Y를 던지기 위해 메서드가 선언될 수 있습니다.이후 버전의 코드에서는 메소드에서 예외 Z를 던질 수 없는데, 이는 새로운 코드가 이전의 사용법과 호환되지 않도록 만들 것이기 때문입니다.확인된 예외를 사용하려면 메서드 호출자가 자신의 throws 절에 Z를 추가하거나 예외를 처리해야 합니다.또는 Z가 X 또는 Y로 잘못 표시될 수도 있습니다.
  • 확장성:계층적 설계에서 각 시스템은 여러 개의 서브시스템을 가질 수 있습니다.각 하위 시스템은 몇 가지 예외를 적용할 수 있습니다.각 상위 시스템은 그 아래에 있는 모든 하위 시스템의 예외를 처리해야 하므로 처리해야 할 예외의 수가 기하급수적으로 늘어납니다.확인된 예외를 사용하려면 이 모든 예외를 명시적으로 처리해야 합니다.

이것들을 해결하기 위해, Hejlsberg는 프로그래머들이 a를 사용함으로써 특징을 우회하는 것에 의존한다고 말합니다.throws Exception선언.다른 우회는 a를 사용하는 것입니다.try { ... } catch (Exception e) {}조련사[37]이를 캐치올 예외 처리 또는 포켓몬 예외 처리라고 하며, 이는 의 캐치프레이즈인 "Em All을 잡아야 한다!"[38]의 이름을 따온 것입니다.자바 튜토리얼은 "처리자가 [39]의도하지 않은" 예외를 잡을 수 있으므로 캐치올 예외 처리를 금지합니다.또 다른 억제된 우회는 모든 예외를 하위 클래스로 만드는 것입니다.RuntimeException.[40]권장되는 해결책은 캐치올 핸들러 또는 던짐 조항을 사용하지만 일반 슈퍼클래스가 아닌 모든 잠재적으로 던져지는 예외의 특정 슈퍼클래스를 사용하는 것입니다[40].Exception. 또 다른 권장 해결책은 호출된[41] 메서드의 추상화 수준에 적합한 예외 유형을 정의 및 선언하고 예외 체인을 사용하여 하위 수준의 예외를 이러한 유형에 매핑하는 것입니다.

유사한 메커니즘

확인된 예외의 근원은 CLU 프로그래밍 언어의 예외 [42]사양 개념으로 돌아갑니다.함수는 해당 유형에 나열된 예외만 나타낼 수 있지만 호출된 함수에서 누출되는 예외는 자동으로 유일한 런타임 예외로 변경됩니다.failure, 컴파일 시간 [43]오류를 초래하는 대신.나중에 Modula-3도 비슷한 [44]기능을 가지고 있었습니다.이러한 기능에는 체크된 [42]예외의 개념에서 중심이 되는 컴파일 시간 확인이 포함되어 있지 않습니다.

C++ 프로그래밍 언어의 초기 버전은 예외 사양이라고 불리는 확인된 예외와 유사한 옵션 메커니즘을 포함했습니다.기본적으로 모든 함수는 어떤 예외도 던질 수 있지만 이는 a에 의해 제한될 수 있습니다.throw함수 서명에 추가되는 절로, 함수가 어떤 예외를 던질 수 있는지 지정합니다.컴파일 시 예외 사양이 적용되지 않았습니다.위반으로 인해 전역 기능이 발생했습니다.std::unexpected부름을 [45]받고 있는함수에 예외가 발생하지 않음을 나타내는 빈 예외 사양이 제공될 수 있습니다.기존 코드를 너무 많이 수정해야 하고 다른 언어로 작성된 코드와의 상호 작용을 방해하며 프로그래머가 로컬 [45]수준에서 너무 많은 핸들러를 쓰도록 유혹할 수 있기 때문에 예외 처리를 언어에 추가할 때 기본값으로 지정되지 않았습니다.그러나 빈 예외 사양을 명시적으로 사용하면 C++ 컴파일러가 상당한 코드 및 스택 레이아웃 최적화를 수행할 수 있으며,[22] 이는 예외 처리가 함수에서 발생할 수 있는 경우에 방지됩니다.일부 분석가들은 C++에서 예외 사양을 적절하게 사용하는 것을 [46]달성하기 어렵다고 여겼습니다.이러한 예외 사양 사용은 C++98 및 C++03에 포함되었으며, 2012년 C++ 언어 표준(C++11)[47]에서 폐지되었으며, C++17의 언어에서는 삭제되었습니다.어떤 예외도 던지지 않는 함수는 이제noexcept키워드.

OCaml 프로그래밍 [48]언어에는 포착되지 않은 예외 분석기가 있습니다.도구는 상승된 예외 집합을 확장형 서명으로 보고합니다.그러나 확인된 예외와 달리 도구는 구문 주석을 필요로 하지 않으며 외부(즉, 예외를 확인하지 않고 프로그램을 컴파일하고 실행할 수 있음)입니다.

예외사항의 동적 확인

예외 처리 루틴의 요점은 코드가 오류 조건을 처리할 수 있도록 보장하는 것입니다.예외 처리 루틴이 충분히 강력하다는 것을 확립하기 위해서는 소프트웨어 결함 주입 및 돌연변이 테스트(때로는 퍼지 테스트라고도 함)를 통해 생성될 수 있는 것과 같이 광범위한 유효하지 않거나 예기치 않은 입력 스펙트럼을 코드에 표시해야 합니다.예외 처리 루틴을 작성하는 가장 어려운 소프트웨어 유형 중 하나는 프로토콜 소프트웨어입니다. 관련 규격을 준수하지 않는 입력을 수신하기 위해 강력한 프로토콜 구현을 준비해야 하기 때문입니다.

소프트웨어 개발 라이프사이클 프로세스 전반에 걸쳐 의미 있는 회귀 분석을 수행할 수 있도록 예외 처리 테스트는 고도로 자동화되어야 하며 테스트 사례는 과학적이고 반복 가능한 방식으로 생성되어야 합니다.이러한 테스트를 수행하는 여러 상용 시스템이 존재합니다.

Java 또는 의 런타임 엔진 환경에서.NET, 런타임 엔진에 연결되는 도구가 있으며, 관심 예외가 발생할 때마다 예외가 발생한 시점에 메모리에 존재했던 디버깅 정보( 스택 및 값)를 기록합니다.이러한 도구를 자동 예외 처리 또는 오류 차단 도구라고 하며 예외에 대한 '근본 원인' 정보를 제공합니다.

비동기 예외

비동기 예외는 Ctrl-C를 눌러 프로그램을 중단하거나 신호를 수신하거나 다른 [49][50]실행 스레드에서 "중지" 또는 "중지"와 같은 중단 메시지를 보내는 등 별도의 스레드 또는 외부 프로세스에 의해 발생하는 이벤트입니다.반면에 동기적 예외는 특정한 경우에 발생합니다.throwstatement, 비동기 예외는 언제든지 제기될 수 있습니다.비동기 예외 처리는 비동기 예외의 부재를 증명할 수 없기 때문에 컴파일러에 의해 최적화될 수 없습니다.또한 리소스 유출을 방지하기 위해 정리 작업 중에 비동기 예외를 차단해야 하기 때문에 올바르게 프로그래밍하기가 어렵습니다.

프로그래밍 언어는 일반적으로 비동기 예외 처리를 피하거나 제한합니다. 예를 들어 C++는 신호 처리기에서 예외를 제기하는 것을 금지하고, Java는 하나의 스레드가 다른 [51]스레드를 중지하도록 허용하는 데 사용된 ThreadDeath 예외의 사용을 중단했습니다.또 다른 기능은 프로그램의 특정 동작 동안에만 비동기 예외를 발생시키는 반비동기 메커니즘입니다.예를 들어 자바의Thread.interrupt()스레드가 다음을 수행하는 작업을 호출할 때만 스레드에 영향을 미칩니다.InterruptedException.[52]유사한[52] POSIXpthread_cancelAPI는 레이스 조건이 있어 [53]안전하게 사용할 수 없습니다.

조건계

Common Lisp, DylanSmalltalk에는 앞서 언급한 예외 처리 시스템을 포괄하는 조건[54] 시스템(Common Lisp Condition System 참조)이 있습니다.이러한 언어 또는 환경에서 조건(켄트 피트먼에 따르면 "오류의 일반화")의 출현은 함수 호출을 의미하며, 예외 처리기의 마지막에 스택을 해제하는 결정을 내릴 수 있습니다.

조건은 예외를 일반화한 것입니다.상태가 발생하면 적절한 상태 처리기를 검색하고 스택 순서로 선택하여 상태를 처리합니다.오류를 나타내지 않는 조건은 안전하게 완전히 처리되지 않을 수 있습니다. 이러한 [55]조건의 유일한 목적은 사용자에게 힌트나 경고를 전파하는 것일 수 있습니다.

지속적 예외

이것은 일부 예외가 연속적이라고 하는, 예외 처리의 소위 재개 모델과 관련이 있습니다: 핸들러에서 시정 조치를 취한 후, 예외를 나타내는 표현으로 복귀하는 것이 허용됩니다.따라서 상태 시스템은 일반화됩니다. 심각하지 않은 상태의 처리기(일명 연속 예외) 내에서 시그널링 표현식과 상태 처리기 사이에 있는 미리 정의된 재시작 지점(일명 재시작)으로 점프할 수 있습니다.재시작은 일부 어휘 환경에서 닫히는 함수로서, 프로그래머가 조건 핸들러를 완전히 종료하기 전에 이 환경을 복구하거나 스택을 부분적으로 푸는 것을 가능하게 해줍니다.

예를 들어 PL/I의 ENDPAGE 조건을 들 수 있습니다. ON 장치는 다음 페이지에 대한 페이지 트레일러 라인과 헤더 라인을 작성한 다음 중단된 코드의 실행을 재개하기 위해 실패할 수 있습니다.

정책과 별도의 메커니즘 재시작

또한 조건 처리는 정책으로부터 메커니즘을 분리합니다.재시작은 오류 복구를 위해 가능한 다양한 메커니즘을 제공하지만 주어진 상황에서 적절한 메커니즘을 선택하지는 않습니다.조건 처리기의 영역으로, (상위 코드에 위치하기 때문에) 더 넓은 뷰에 액세스할 수 있습니다.

예:단일 syslog 파일 항목을 구문 분석하는 것이 목적인 라이브러리 함수가 있다고 가정합니다.항목의 형식이 잘못된 경우 이 기능을 수행해야 합니까?같은 라이브러리가 여러 가지 목적으로 프로그램에 배치될 수 있기 때문에 정답은 없습니다.대화형 로그 파일 브라우저에서 올바른 작업은 사용자가 볼 수 있도록 항목을 구문 분석하지 않고 반환하는 것일 수 있지만 자동 로그 요약 프로그램에서는 읽을 수 없는 필드에 대한 null 값을 제공하는 것이 올바른 작업일 수 있지만 너무 많은 항목의 형식이 잘못된 경우 오류가 발생하여 중단됩니다.

즉, 범용도서관 기능에 알려지지 않은 프로그램의 보다 넓은 목표라는 측면에서만 질문에 답할 수 있습니다.그럼에도 불구하고 오류 메시지와 함께 종료하는 것은 정답이 될 수 있는 경우가 거의 없습니다.따라서 단순히 오류로 종료하는 대신 함수는 로그 항목을 건너뛰거나, 읽을 수 없는 필드에 대한 기본값 또는 null 값을 제공하거나, 사용자에게 누락된 값을 요청하거나, 스택을 풀고 오류 메시지와 함께 처리를 중단하는 등 다양한 방법을 제공하는 재시작을 설정할 수 있습니다.제공되는 재시작은 오류 복구에 사용할 수 있는 메커니즘을 구성하며, 조건 처리기에 의한 재시작 선택은 정책을 제공합니다.

비평

예외 처리는 소프트웨어에서 올바르게 처리되지 않는 경우가 많습니다. 특히 예외 소스가 여러 개 있는 경우, Java 코드의 500만 줄에 대한 데이터 흐름 분석에서 1300개 이상의 예외 처리 [12]결함이 발견되었습니다.바이머와 네큘라는 다른 사람들의 여러 선행 연구(1999-2004)와 그들의 결과를 인용하면서 예외의 중요한 문제는 "프로그래머들이 [12]: 8:27 추론하기 어려운 숨겨진 제어 흐름 경로를 만든다"는 것이라고 썼습니다."try-catch-finally는 개념적으로 간단하지만, 그것은 언어 사양에서 실행 설명이 가장 복잡하며 [Gosling et al. 1996] 공식 영어 설명에서 4단계의 중첩된 "if"를 요구합니다.한마디로 프로그래머들이 [12]: 8:13–8:14 간과하는 코너 케이스가 대거 포함돼 있습니다."

예외적으로 비정형 흐름은 리소스 유출(: 뮤텍스에 의해 잠긴 섹션을 탈출하거나 파일을 일시적으로 열고 있는 섹션) 또는 일관되지 않은 상태의 위험을 증가시킵니다.예외가 있는 경우 리소스 관리를 위한 다양한 기술이 있으며, 가장 일반적으로 폐기 패턴과 어떤 형태의 언윈드 보호를 결합합니다(예:finallyclause). 이것은 컨트롤이 코드의 섹션을 종료할 때 자동으로 리소스를 해제합니다.

1980년에 Tony Hoare는 Ada 프로그래밍 언어가 "...많은 기능과 표기 규칙을 가지고 있으며, 대부분은 불필요하고 일부는 예외 처리와 같은 위험한 기능을 가지고 있습니다. [...] 현재 상태의 이 언어가 신뢰성이 중요한 애플리케이션에서 사용되지 않도록 하십시오. [...]프로그래밍 언어 오류의 결과로 잘못 된 다음 로켓은 무해한 금성 여행을 하는 탐사용 우주 로켓이 아닐 수도 있습니다: 그것은 우리의 [56]도시들 중 한 곳에서 폭발하는 핵탄두일지도 모릅니다."

바둑 개발자들은 끝판왕이라는 관용구가 통제 [57]흐름을 혼란스럽게 한다고 생각하고 예외적인 것을 도입했습니다.panic/recover매커니즘[58] recover()다르다catch그것이 오직 a 내부에서만 호출될 수 있다는 점에서.defer함수의 코드 블록을 만들어서 핸들러는 함수의 반환 값을 정리하고 변경할 수 있을 뿐, 함수 [59]내의 임의의 지점으로 제어를 반환할 수 없습니다.defer블록 자체는 a와 유사한 기능을 합니다.finally

참고 항목

메모들

  1. ^ PL/나는 동적 범위 예외를 사용했습니다.PL/I 예외 처리에는 주의, 파일 끝, 나열된 [citation needed]변수 수정 등 오류가 아닌 이벤트가 포함되었습니다.
  2. ^ 예를 들어 PL/I에서 예외 처리기의 정상 종료는 스택을 풉니다.
  3. ^ 예외가 없는 경우에만 "제로 [처리] 비용"이 발생합니다(조회 테이블에 메모리가 필요하므로 메모리 비용이 발생합니다).예외가 발생하는 경우(즉, 다음과 같은 경우) 비용이 발생합니다.throw실행됩니다).예외 처리를 구현하면 수행할 수 있는 컴파일러 최적화가 제한될 수도 있습니다.

참고문헌

  1. ^ a b c d Kiniry, J. R. (2006). "Exceptions in Java and Eiffel: Two Extremes in Exception Design and Application". Advanced Topics in Exception Handling Techniques (PDF). Lecture Notes in Computer Science. Vol. 4119. pp. 288–300. doi:10.1007/11818502_16. ISBN 978-3-540-37443-5.
  2. ^ "Built-in Exceptions — Python 3.10.4 documentation". docs.python.org. Retrieved 17 May 2022.
  3. ^ "Stroustrup: C++ Style and Technique FAQ". www.stroustrup.com. Archived from the original on 2 February 2018. Retrieved 5 May 2018.
  4. ^ Bloch, Joshua (2008). "Item 57: Use exceptions only for exceptional situations". Effective Java (Second ed.). Addison-Wesley. p. 241. ISBN 978-0-321-35668-0.
  5. ^ McCarthy, John (12 February 1979). "History of Lisp". www-formal.stanford.edu. Retrieved 13 January 2022.
  6. ^ McCarthy, John; Levin, Michael I.; Abrahams, Paul W.; Edwards, Daniel J.; Hart, Timothy P. (14 July 1961). LISP 1.5 programmer's manual (PDF). Retrieved 13 January 2022.
  7. ^ "The ON Statement" (PDF). IBM System/360 Operating System, PL/I Language Specifications (PDF). IBM. July 1966. p. 120. C28-6571-3.
  8. ^ Gabriel & Steel 2008, 페이지 3.
  9. ^ 화이트 1979, 페이지 194.
  10. ^ a b Strousttrup 1994, 페이지 392.
  11. ^ Stroustrup, Bjarne. "C++ Style and Technique FAQ". www.stroustrup.com. Retrieved 12 January 2022.
  12. ^ a b c d Weimer, W; Necula, G.C. (2008). "Exceptional Situations and Program Reliability" (PDF). ACM Transactions on Programming Languages and Systems. Vol. 30, no. 2. Archived (PDF) from the original on 2015-09-23.
  13. ^ Roberts, Eric S. (21 March 1989). "Implementing Exceptions in C" (PDF). DEC Systems Research Center. SRC-RR-40. Retrieved 4 January 2022. {{cite journal}}:저널 요구사항 인용 journal=(도움말)
  14. ^ Christiansen, Tom; Torkington, Nathan (2003). "10.12. Handling Exceptions". Perl cookbook (2nd ed.). Beijing: O'Reilly. ISBN 0-596-00313-7.
  15. ^ Strousttrup 1994, 16.6 예외 처리: 재개 vs.종료, 페이지 390-393.
  16. ^ "R: Condition Handling and Recovery". search.r-project.org. Retrieved 2022-12-05.
  17. ^ 스캇 마이어스, 가장 중요한 C++ 소프트웨어...2011-04-28 Wayback Machine, 2006년에 아카이브 완료
  18. ^ D. 카메론, P. 파우스트, D.렌코프, M.Mehta, "C++ 예외 처리의 휴대용 구현", Pedues of the C++ Conference (1992년 8월) USENIX.
  19. ^ Peter Kleissner (February 14, 2009). "Windows Exception Handling - Peter Kleissner". Archived from the original on October 14, 2013. Retrieved 2009-11-21.Peter Kleissner (February 14, 2009). "Windows Exception Handling - Peter Kleissner". Archived from the original on October 14, 2013. Retrieved 2009-11-21.컴파일러 기반 Structured Exception Handling 섹션
  20. ^ Graham Hutton, Joel Wright, "Compiling Exceptions Correct Archived 2014-09-11 at the Wayback Machine".2004년 제7회 국제 프로그램 구성 수학 회의 진행
  21. ^ Lajoie, Josée (March–April 1994). "Exception handling – Supporting the runtime mechanism". C++ Report. 6 (3).
  22. ^ a b Schilling, Jonathan L. (August 1998). "Optimizing away C++ exception handling". SIGPLAN Notices. 33 (8): 40–47. doi:10.1145/286385.286390. S2CID 1522664.
  23. ^ "Modern C++ best practices for exceptions and error handling". Microsoft. 8 March 2021. Retrieved 21 March 2022.
  24. ^ a b Stroustrup, Bjarne (18 November 2019). "C++ exceptions and alternatives" (PDF). Retrieved 23 March 2022.
  25. ^ M. Hof, H. Mössenböck, P. Pirkelbauer, "웨이백 머신에서 메타프로그래밍을 사용한 제로 오버헤드 예외 처리 2016-03-03 아카이브", SOFSEM'97, 1997년 11월, 컴퓨터 과학 강의 노트 1338, 페이지 423-431.
  26. ^ 모든 예외는 해결됩니다, 짐 윌콕스
  27. ^ a b c Mac Developer Library, "Wayback Machine에서 2016-03-04 보관된 미발견 예외"
  28. ^ MSDN, AppDomain.Wayback Machine에서 처리되지 않은 예외 이벤트가 2016-03-04 보관됨
  29. ^ 파이썬 튜토리얼, "8. Wayback Machine에서 2015-09-01 오류예외 보관"
  30. ^ "Java Practices -> Provide an uncaught exception handler". www.javapractices.com. Archived from the original on 9 September 2016. Retrieved 5 May 2018.
  31. ^ PyMOTW(Python Module Of The Week), "웨이백 머신에서 보관된 예외 처리 2015-09-15"
  32. ^ "Google Answers: The origin of checked exceptions". Archived from the original on 2011-08-06. Retrieved 2011-12-15.
  33. ^ Java 언어 규격, 11.2장 http://java.sun.com/docs/books/jls/third_edition/html/exceptions.html#11.2 Wayback Machine에서 2006-12-08 보관
  34. ^ Mössenböck, Hanspeter (2002-03-25). "Advanced C#: Variable Number of Parameters" (PDF). Institut für Systemsoftware, Johannes Kepler Universität Linz, Fachbereich Informatik. p. 32. Archived (PDF) from the original on 2011-09-20. Retrieved 2011-08-05.
  35. ^ a b c Eckel, Bruce (2006). Thinking in Java (4th ed.). Upper Saddle River, NJ: Prentice Hall. pp. 347–348. ISBN 0-13-187248-6.
  36. ^ Gunnerson, Eric (9 November 2000). "C# and exception specifications". Archived from the original on 1 January 2006.
  37. ^ a b Bill Venners; Bruce Eckel (August 18, 2003). "The Trouble with Checked Exceptions: A Conversation with Anders Hejlsberg, Part II". Retrieved 4 January 2022.
  38. ^ Juneau, Josh (31 May 2017). Java 9 Recipes: A Problem-Solution Approach. Apress. p. 226. ISBN 978-1-4842-1976-8.
  39. ^ "Advantages of Exceptions (The Java™ Tutorials : Essential Classes : Exceptions)". Download.oracle.com. Archived from the original on 2011-10-26. Retrieved 2011-12-15.
  40. ^ "Unchecked Exceptions – The Controversy (The Java™ Tutorials : Essential Classes : Exceptions)". Download.oracle.com. Archived from the original on 2011-11-17. Retrieved 2011-12-15.
  41. ^ Bloch 2001:178 Bloch, Joshua (2001). Effective Java Programming Language Guide. Addison-Wesley Professional. ISBN 978-0-201-31005-4.
  42. ^ a b "Bruce Eckel's MindView, Inc: Does Java need Checked Exceptions?". Mindview.net. Archived from the original on 2002-04-05. Retrieved 2011-12-15.
  43. ^ Liskov, B.H.; Snyder, A. (November 1979). "Exception Handling in CLU" (PDF). IEEE Transactions on Software Engineering. SE-5 (6): 546–558. doi:10.1109/TSE.1979.230191. S2CID 15506879. Retrieved 19 December 2021.
  44. ^ "Modula-3 - Procedure Types". .cs.columbia.edu. 1995-03-08. Archived from the original on 2008-05-09. Retrieved 2011-12-15.
  45. ^ a b Bjarne Stroustrup, The C++ 프로그래밍 언어 제3판, Addison Wesley, 1997ISBN 0-201-88954-4. pp. 375-380.
  46. ^ Reeves, J.W. (July 1996). "Ten Guidelines for Exception Specifications". C++ Report. 8 (7).
  47. ^ Sutter, Herb (3 March 2010). "Trip Report: March 2010 ISO C++ Standards Meeting". Archived from the original on 23 March 2010. Retrieved 24 March 2010.
  48. ^ "OcamlExc - An uncaught exceptions analyzer for Objective Caml". Caml.inria.fr. Archived from the original on 2011-08-06. Retrieved 2011-12-15.
  49. ^ "Asynchronous Exceptions in Haskell - Marlow, Jones, Moran (ResearchIndex)". Citeseer.ist.psu.edu. Archived from the original on 2011-02-23. Retrieved 2011-12-15.
  50. ^ Freund, Stephen N.; Mitchell, Mark P. "Safe Asynchronous Exceptions For Python" (PDF). Retrieved 4 January 2022. {{cite journal}}:저널 요구사항 인용 journal=(도움말)
  51. ^ "Java Thread Primitive Deprecation". Java.sun.com. Archived from the original on 2009-04-26. Retrieved 2011-12-15.
  52. ^ "Interrupts (The Java™ Tutorials > Essential Java Classes > Concurrency)". docs.oracle.com. Retrieved 5 January 2022.
  53. ^ Felker, Rich. "Thread cancellation and resource leaks". ewontfix.com. Retrieved 5 January 2022.
  54. ^ What Conditions (Exceptions) are Really About (2008-03-24). "What Conditions (Exceptions) are Really About". Danweinreb.org. Archived from the original on February 1, 2013. Retrieved 2014-09-18.
  55. ^ "Condition System Concepts". Franz.com. 2009-07-21. Archived from the original on 2007-06-28. Retrieved 2011-12-15.
  56. ^ C.A.R. Hoare.'황제의 헌 옷'.1980 튜링상 강연
  57. ^ "Frequently Asked Questions". Archived from the original on 2017-05-03. Retrieved 2017-04-27. We believe that coupling exceptions to a control structure, as in the try-catch-finally idiom, results in convoluted code. It also tends to encourage programmers to label too many ordinary errors, such as failing to open a file, as exceptional.
  58. ^ Wayback Machine, Go wiki에서 패닉리커버리 Archive 2013-10-10-24
  59. ^ Bendersky, Eli (8 August 2018). "On the uses and misuses of panics in Go". Eli Bendersky's website. Retrieved 5 January 2022. The specific limitation is that recover can only be called in a defer code block, which cannot return control to an arbitrary point, but can only do clean-ups and tweak the function's return values.

인용작품