다른 소프트웨어 엔지니어링 분야에는 라이브러리가 오류 또는 기타 예외적 인 조건을 처리하는 방법에 대한 철학이 많이 있습니다. 내가 본 몇 가지 :
- 포인터 인수가 반환 한 결과와 함께 오류 코드를 반환합니다. 이것이 PETSc가하는 일입니다.
- 센티넬 값으로 오류를 반환합니다. 예를 들어, malloc은 메모리를 할당 할 수 없으면 NULL
sqrt
을 반환하고 음수를 전달하면 NaN을 반환합니다.이 방법은 많은 libc 함수에서 사용됩니다. - 예외를 던지십시오. 거래 II, Trilinos 등에서 사용
- 변형 유형을 반환합니다. 예를 들어,
Result
올바르게 실행되면 유형의 객체를 반환 하고 유형Error
을 사용하여 실패한 방법을 설명하는 C ++ 함수가 반환 됩니다std::variant<Error, Result>
. - assert와 crash를 사용하십시오. p4est 및 igraph의 일부에서 사용됩니다.
각 접근 방식의 문제점 :
- 모든 오류를 검사하면 추가 코드가 많이 발생합니다. 결과가 저장 될 값은 항상 먼저 선언되어야하며 한 번만 사용될 수있는 많은 임시 변수가 도입됩니다. 이 접근 방식은 어떤 오류가 발생했는지 설명하지만 심층 통화 스택의 위치 또는 이유를 결정하기 어려울 수 있습니다.
- 오류 사례는 무시하기 쉽습니다. 또한 전체 출력 유형 범위가 그럴듯한 결과 인 경우 많은 함수가 의미있는 센티넬 값을 가질 수 없습니다. # 1과 동일한 문제가 많습니다.
- C 또는 Fortran이 아닌 C ++, Python 등에서 만 가능합니다. setjmp / longjmp sorcery 또는 libunwind를 사용하여 C에서 흉내낼 수 있습니다 .
- C 또는 Fortran이 아닌 C ++, Rust, OCaml 등에서 만 가능합니다. 매크로 마법을 사용하여 C에서 흉내낼 수 있습니다.
- 아마도 가장 유익한 정보 일 것입니다. 그러나 파이썬 래퍼를 작성하는 C 라이브러리 에이 접근법을 채택하면 범위를 벗어난 인덱스를 배열에 전달하는 것과 같은 어리석은 실수로 인해 파이썬 인터프리터가 충돌합니다.
인터넷에서 오류 처리에 대한 많은 조언은 운영 체제, 임베디드 개발 또는 웹 응용 프로그램의 관점에서 작성되었습니다. 충돌은 용납 할 수 없으며 보안에 대해 걱정해야합니다. 과학적 응용 프로그램은 이러한 문제가 거의 같은 정도로 거의 없습니다.
또 다른 고려 사항은 어떤 종류의 오류를 복구 할 수 있는지 여부입니다. malloc 실패는 복구 할 수 없으며, 어떠한 경우에도 OS 메모리 부족 킬러가이를 수행합니다. 배열 크기에 대한 범위를 벗어난 인덱스도 복구 할 수 없습니다. 사용자에게는 라이브러리가 할 수있는 가장 좋은 일은 유익한 오류 메시지로 충돌하는 것입니다. 한편, 직접 선형 분해 솔버를 사용하면 반복 선형 솔버가 수렴하지 못하는 것을 복구 할 수 있습니다.
과학 라이브러리는 오류를 어떻게보고하고 처리해야합니까? 물론 라이브러리가 어떤 언어로 구현되는지에 달려 있다는 것을 알고 있습니다. 그러나 충분히 유용한 라이브러리에 대해서는 사람들이 구현 한 언어가 아닌 다른 언어로 호출하기를 원할 것입니다.
따로, C 라이브러리에서 전역 어설 션 핸들러 함수 포인터를 공개 API의 일부로 정의하면 접근법 # 5가 실질적으로 향상 될 수 있다고 생각합니다. 어설 션 처리기는 기본적으로보고 파일 / 줄 번호 및 충돌로 설정됩니다. 이 라이브러리의 C ++ 바인딩은 대신 C ++ 예외를 발생시키는 새로운 어설 션 핸들러를 정의합니다. 마찬가지로 Python 바인딩은 CPython API를 사용하여 Python 예외를 발생시키는 어설 션 핸들러를 정의합니다. 그러나 나는이 접근법을 취하는 예를 모른다.