문제 :
오랜 시간이 지난 지금, 나는 그 exceptions
메커니즘이 실제로 해결되어야한다고 생각하지 않기 때문에 메커니즘 에 대해 걱정하고 있습니다.
CLAIM :이 주제와 관련하여 오랫동안 논란이 있었으며 대부분은 exceptions
오류 코드 를 비교하고 반환하는 데 어려움을 겪고 있습니다. 이것은 분명히 여기의 주제가 아닙니다.
오류를 정의하려고하면 Bjarne Stroustrup & Herb Sutter의 CppCoreGuidelines에 동의합니다.
오류는 기능이 광고 목적을 달성 할 수 없음을 의미합니다
CLAIM :이 exception
메커니즘은 오류 처리를위한 언어 의미입니다.
CLAIM : 과제를 달성하지 못한 기능에 대해서는 "변명 없음"이 있습니다 : 사전 / 사후 조건을 잘못 정의하여 기능이 결과를 보장 할 수 없거나 일부 예외적 인 경우가 개발에 시간을 소비하기에 충분히 중요한 것으로 간주되지 않음 해결책. IMO를 고려할 때 일반 코드와 오류 코드 처리의 차이점은 (구현 전) 매우 주관적인 선입니다.
CLAIM : 사전 또는 사후 조건이 유지되지 않는 경우를 표시하기 위해 예외를 사용하는 것이 exception
메커니즘 의 또 다른 목적 , 주로 디버깅 목적입니다. 나는이 사용법을 목표로하지 않습니다 exceptions
.
많은 서적, 자습서 및 기타 소스에서 오류 처리는 상당히 객관적인 과학으로 표시되는 경향이 있으며, 이는 해결 된 exceptions
것이며 catch
모든 상황에서 복구 할 수있는 강력한 소프트웨어 를 제공 하기 위해 필요 합니다. 그러나 개발자로서 몇 년 동안 다른 접근 방식으로 문제를 볼 수 있습니다.
- 프로그래머는 특정 사례를 신중하게 구현하기에는 너무 드물게 보일 때 예외를 던져서 작업을 단순화하는 경향이 있습니다. 일반적인 경우는 메모리 부족 문제, 디스크 가득 참 문제, 손상된 파일 문제 등입니다. 충분할 수도 있지만 항상 아키텍처 수준에서 결정되는 것은 아닙니다.
- 프로그래머는 라이브러리의 예외에 대한 문서를주의 깊게 읽지 않으며 일반적으로 함수가 언제 언제 발생하는지 알지 못합니다. 또한, 그들이 알더라도 실제로 관리하지 않습니다.
- 프로그래머는 조기에 예외를 포착하지 않는 경향이 있으며, 그렇게 할 때는 대부분 로그를 작성하고 추가로 처리해야합니다. (첫 번째 포인트 참조).
두 가지 결과가 있습니다.
- 자주 발생하는 오류는 개발 초기에 감지되어 디버깅됩니다 (좋은).
- 드문 예외는 관리되지 않으며 사용자 홈에서 시스템이 멋진 로그 메시지와 함께 충돌하게합니다. 때때로 오류가보고되거나보고되지 않습니다.
이를 고려할 때 IMO 오류 메커니즘의 주요 목적은 다음과 같아야합니다.
- 특정 사례가 관리되지 않는 코드에 표시하십시오.
- 이 상황이 발생하면 이슈 런타임을 관련 코드 (적어도 발신자)에게 알리십시오.
- 복구 메커니즘을 제공합니다
exception
오류 처리 메커니즘으로서의 의미론 의 주요 결함 은 IMO입니다. throw
소스 코드 에서 a 가 어디에 있는지 쉽게 알 수 있지만 선언을 보면 특정 함수가 발생할 수 있는지 알 수 없습니다. 이것은 위에서 소개 한 모든 문제를 가져옵니다.
언어는 언어의 다른 측면 (예 : 강력한 변수 유형)에 대해 오류 코드를 엄격하게 시행하고 확인하지 않습니다.
해결책을위한 시도
이를 개선하기 위해 매우 간단한 오류 처리 시스템을 개발했습니다.이 오류 처리 시스템은 오류 처리를 일반 코드와 동일한 수준으로 중요하게 만듭니다.
아이디어는 다음과 같습니다.
- 각각의 (관련된) 기능은
success
매우 가벼운 물체에 대한 참조를 수신하고 경우에 따라 오류 상태로 설정할 수 있습니다. 텍스트 오류가 저장 될 때까지 개체가 매우 밝습니다. - 제공된 객체에 이미 오류가있는 경우 함수는 해당 작업을 건너 뛰는 것이 좋습니다.
- 오류를 무시해서는 안됩니다.
전체 디자인은 각 측면 (약 10 페이지)과 OOP에 적용하는 방법을 철저히 고려합니다.
Success
수업의 예 :
class Success
{
public:
enum SuccessStatus
{
ok = 0, // All is fine
error = 1, // Any error has been reached
uninitialized = 2, // Initialization is required
finished = 3, // This object already performed its task and is not useful anymore
unimplemented = 4, // This feature is not implemented already
};
Success(){}
Success( const Success& v);
virtual ~Success() = default;
virtual Success& operator= (const Success& v);
// Comparators
virtual bool operator==( const Success& s)const { return (this->status==s.status && this->stateStr==s.stateStr);}
virtual bool operator!=( const Success& s)const { return (this->status!=s.status || this->stateStr==s.stateStr);}
// Retrieve if the status is not "ok"
virtual bool operator!() const { return status!=ok;}
// Retrieve if the status is "ok"
operator bool() const { return status==ok;}
// Set a new status
virtual Success& set( SuccessStatus status, std::string msg="");
virtual void reset();
virtual std::string toString() const{ return stateStr;}
virtual SuccessStatus getStatus() const { return status; }
virtual operator SuccessStatus() const { return status; }
private:
std::string stateStr;
SuccessStatus status = Success::ok;
};
용법:
double mySqrt( Success& s, double v)
{
double result = 0.0;
if (!s) ; // do nothing
else if (v<0.0) s.set(Error, "Square root require non-negative input.");
else result = std::sqrt(v);
return result;
}
Success s;
mySqrt(s, 144.0);
otherStuff(s);
saveStuff(s);
if (s) /*All is good*/;
else cout << s << endl;
나는 그것을 내 (자신의) 많은 코드에서 사용했고 프로그래머 (me)가 예외적 인 경우와 그 해결 방법 (좋은)에 대해 더 생각하도록 강요했습니다. 그러나 학습 곡선이 있으며이를 사용하는 코드와 잘 통합되지 않습니다.
질문
프로젝트에서 그러한 패러다임을 사용하는 의미를 더 잘 이해하고 싶습니다.
- 문제의 전제가 정확합니까? 또는 관련된 것을 놓쳤습니까?
- 솔루션이 좋은 건축 아이디어입니까? 아니면 가격이 너무 높습니까?
편집하다:
방법 비교 :
//Exceptions:
// Incorrect
File f = open("text.txt"); // Could throw but nothing tell it! Will crash
save(f);
// Correct
File f;
try
{
f = open("text.txt");
save(f);
}
catch( ... )
{
// do something
}
//Error code (mixed):
// Incorrect
File f = open("text.txt"); //Nothing tell you it may fail! Will crash
save(f);
// Correct
File f = open("text.txt");
if (f) save(f);
//Error code (pure);
// Incorrect
File f;
open(f, "text.txt"); //Easy to forget the return value! will crash
save(f);
//Correct
File f;
Error er = open(f, "text.txt");
if (!er) save(f);
//Success mechanism:
Success s;
File f;
open(s, "text.txt");
save(s, f); //s cannot be avoided, will never crash.
if (s) ... //optional. If you created s, you probably don't forget it.