C ++ 예외를 발생시키는 방법 다음과 같이 함수를 정의했습니다. int

예외 처리에 대한 이해가 매우 부족합니다 (예 : 내 목적에 맞게 throw, try, catch 문을 사용자 정의하는 방법).

예를 들어 다음과 같이 함수를 정의했습니다. int compare(int a, int b){...}

a 또는 b가 음수 일 때 일부 메시지에서 예외를 발생시키는 함수를 원합니다.

함수 정의에서 어떻게 접근해야합니까?



답변

단순한:

#include <stdexcept>

int compare( int a, int b ) {
    if ( a < 0 || b < 0 ) {
        throw std::invalid_argument( "received negative value" );
    }
}

표준 라이브러리에는 던질 수 있는 멋진 내장 예외 개체 모음이 제공됩니다 . 당신은 항상 가치에 의해 던져 참조로 잡아야한다는 것을 명심하십시오 :

try {
    compare( -1, 3 );
}
catch( const std::invalid_argument& e ) {
    // do stuff with exception... 
}

각 시도 후에 여러 catch () 문을 가질 수 있으므로 원하는 경우 다른 예외 유형을 개별적으로 처리 할 수 ​​있습니다.

예외를 다시 던질 수도 있습니다.

catch( const std::invalid_argument& e ) {
    // do something

    // let someone higher up the call stack handle it if they want
    throw;
}

그리고 유형에 관계없이 예외를 잡으려면 :

catch( ... ) { };


답변

throw필요한 곳에 추가 try하고 오류를 처리하는 발신자를 차단하십시오. 관습에 따라에서 파생 된 것만 던져야 std::exception하므로 <stdexcept>먼저 포함하십시오 .

int compare(int a, int b) {
    if (a < 0 || b < 0) {
        throw std::invalid_argument("a or b negative");
    }
}

void foo() {
    try {
        compare(-1, 0);
    } catch (const std::invalid_argument& e) {
        // ...
    }
}

또한 Boost.Exception을 살펴 보십시오 .


답변

이 질문은 다소 오래되었지만 이미 답변되었지만 C ++ 11에서 적절한 예외 처리를 수행하는 방법에 대한 메모를 추가하고 싶습니다.

사용 std::nested_exceptionstd::throw_with_nested

여기여기 에 스택 오버플로에 설명되어 있으며 중첩 된 예외를 다시 던질 적절한 예외 처리기를 작성하여 디버거 또는 번거로운 로깅없이 코드 내부의 예외에 대한 역 추적을 얻는 방법에 대해 설명합니다 .

파생 된 예외 클래스로이 작업을 수행 할 수 있으므로 이러한 역 추적에 많은 정보를 추가 할 수 있습니다! 역 추적이 다음과 같은 GitHub 에서 내 MWE를 살펴볼 수도 있습니다 .

Library API: Exception caught in function 'api_function'
Backtrace:
~/Git/mwe-cpp-exception/src/detail/Library.cpp:17 : library_function failed
~/Git/mwe-cpp-exception/src/detail/Library.cpp:13 : could not open file "nonexistent.txt"


답변

특정 오류가 발생할 때 발생하는 메시지를 정의 할 수 있습니다.

throw std::invalid_argument( "received negative value" );

또는 다음과 같이 정의 할 수 있습니다.

std::runtime_error greatScott("Great Scott!");
double getEnergySync(int year) {
    if (year == 1955 || year == 1885) throw greatScott;
    return 1.21e9;
}                                                       

일반적으로 다음 try ... catch과 같은 블록이 있습니다.

try {
// do something that causes an exception
}catch (std::exception& e){ std::cerr << "exception: " << e.what() << std::endl; }


답변

사용자 정의 예외 의 경우 여기에 설명 된 다른 답변 에 추가 하고 싶었습니다 .

std::exception“모든 가능한”예외 유형을 발견 할 때로 부터 파생되는 사용자 정의 예외를 작성하는 경우, 항상 catch포착 될 수있는 “가장 파생 된”예외 유형으로 절을 시작해야합니다 . 하지 말아야 할 것의 예를보십시오 :

#include <iostream>
#include <string>

using namespace std;

class MyException : public exception
{
public:
    MyException(const string& msg) : m_msg(msg)
    {
        cout << "MyException::MyException - set m_msg to:" << m_msg << endl;
    }

   ~MyException()
   {
        cout << "MyException::~MyException" << endl;
   }

   virtual const char* what() const throw ()
   {
        cout << "MyException - what" << endl;
        return m_msg.c_str();
   }

   const string m_msg;
};

void throwDerivedException()
{
    cout << "throwDerivedException - thrown a derived exception" << endl;
    string execptionMessage("MyException thrown");
    throw (MyException(execptionMessage));
}

void illustrateDerivedExceptionCatch()
{
    cout << "illustrateDerivedExceptionsCatch - start" << endl;
    try
    {
        throwDerivedException();
    }
    catch (const exception& e)
    {
        cout << "illustrateDerivedExceptionsCatch - caught an std::exception, e.what:" << e.what() << endl;
        // some additional code due to the fact that std::exception was thrown...
    }
    catch(const MyException& e)
    {
        cout << "illustrateDerivedExceptionsCatch - caught an MyException, e.what::" << e.what() << endl;
        // some additional code due to the fact that MyException was thrown...
    }

    cout << "illustrateDerivedExceptionsCatch - end" << endl;
}

int main(int argc, char** argv)
{
    cout << "main - start" << endl;
    illustrateDerivedExceptionCatch();
    cout << "main - end" << endl;
    return 0;
}

노트:

0)은 적절한 순서 ie- 먼저, 반대로되어야 catch (const MyException& e)하였다된다 catch (const std::exception& e).

당신이 볼 수 있듯이 같이 프로그램을 실행할 때 1), 첫 번째 캐치 절은 않았다 아마 무엇 인 (실행됩니다 NOT ) 처음에 싶었다.

2) 첫 번째 catch 절에서 잡은 유형이 유형이더라도 std::exception“적절한”버전 what()이 호출됩니다. 참조에 의해 잡히게됩니다 (적어도 잡힌 인수 std::exception유형을 값으로 변경 함) . “개체 슬라이싱”현상).

3) “XXX 예외가 발생했기 때문에 일부 코드 …”가 예외 유형과 관련하여 중요한 작업을 수행하는 경우 여기에 코드의 오작동이 있습니다.

4) 이것은 잡힌 물체가 다음 class Base{};과 같은 “정상적인”물체 인 경우에도 관련이 있습니다 class Derived : public Base {}.

5) g++ 7.3.0Ubuntu 18.04.1에서 언급 된 문제를 나타내는 경고가 생성됩니다.

‘void describeDerivedExceptionCatch ()’함수에서 : item12Linux.cpp : 48 : 2 : 경고 : ‘MyException’유형의 예외 가 catch됩니다 (const MyException & e) ^ ~~~~

item12Linux.cpp : 43 : 2 : 경고 : ‘std :: exception’catch
(const exception & e) ^ ~~~~의 이전 핸들러에서

다시 말하지만 ,이 답변은 여기에 설명 된 다른 답변 에 추가 하는 것입니다 (이 시점은 언급 할 가치가 있다고 생각했지만 의견으로는 묘사 할 수 없습니다).


답변