C ++ 예외 : std :: string 던지기 { if(!QueryPerformanceTimer(&m_baz)) {

내 C ++ 메서드가 이상하고 복구 할 수없는 경우 예외를 throw하고 싶습니다. std::string포인터 를 던져도 괜찮 습니까?

제가 기대했던 작업은 다음과 같습니다.

void Foo::Bar() {
    if(!QueryPerformanceTimer(&m_baz)) {
        throw new std::string("it's the end of the world!");
    }
}

void Foo::Caller() {
    try {
        this->Bar(); // should throw
    }
    catch(std::string *caught) { // not quite sure the syntax is OK here...
        std::cout << "Got " << caught << std::endl;
    }
}



답변

예. std::exceptionC ++ 표준 라이브러리의 기본 예외 클래스입니다. 문자열 자체는 사용 중에 예외를 throw 할 수 있으므로 예외 클래스로 사용하지 않는 것이 좋습니다. 그럴 경우 어디에 계십니까?

boost에는 예외 및 오류 처리에 대한 좋은 스타일에 대한 훌륭한 문서 가 있습니다. 읽을 가치가 있습니다.


답변

몇 가지 원칙 :

  1. std :: exception 기본 클래스가 있으면 예외가 파생되도록해야합니다. 그런 식으로 일반 예외 처리기는 여전히 몇 가지 정보를 가지고 있습니다.

  2. 포인터를 던지지 말고 객체를 던지십시오. 그렇게하면 메모리가 처리됩니다.

예:

struct MyException : public std::exception
{
   std::string s;
   MyException(std::string ss) : s(ss) {}
   ~MyException() throw () {} // Updated
   const char* what() const throw() { return s.c_str(); }
};

그런 다음 코드에서 사용하십시오.

void Foo::Bar(){
  if(!QueryPerformanceTimer(&m_baz)){
    throw MyException("it's the end of the world!");
  }
}

void Foo::Caller(){
  try{
    this->Bar();// should throw
  }catch(MyException& caught){
    std::cout<<"Got "<<caught.what()<<std::endl;
  }
}


답변

이 모든 작업 :

#include <iostream>
using namespace std;

//Good, because manual memory management isn't needed and this uses
//less heap memory (or no heap memory) so this is safer if
//used in a low memory situation
void f() { throw string("foo"); }

//Valid, but avoid manual memory management if there's no reason to use it
void g() { throw new string("foo"); }

//Best.  Just a pointer to a string literal, so no allocation is needed,
//saving on cleanup, and removing a chance for an allocation to fail.
void h() { throw "foo"; }

int main() {
  try { f(); } catch (string s) { cout << s << endl; }
  try { g(); } catch (string* s) { cout << *s << endl; delete s; }
  try { h(); } catch (const char* s) { cout << s << endl; }
  return 0;
}

h보다 f보다 g를 선호해야합니다. 가장 바람직하지 않은 옵션에서는 메모리를 명시 적으로 해제해야합니다.


답변

작동하지만 내가 너라면 안 할거야 완료되었을 때 해당 힙 데이터를 삭제하지 않는 것 같습니다. 즉, 메모리 누수가 발생했음을 의미합니다. C ++ 컴파일러는 스택이 팝되는 경우에도 예외 데이터가 유지되도록 관리하므로 힙을 사용해야한다고 생각하지 마십시오.

덧붙여서, 던지기는 std::string시작하기에 가장 좋은 방법은 아닙니다. 간단한 래퍼 개체를 사용하면 길을 따라 훨씬 더 많은 유연성을 얻을 수 있습니다. 지금은 a string를 캡슐화 할 수 있지만 나중에 예외를 발생시킨 일부 데이터 또는 줄 번호 (매우 일반적)와 같은 다른 정보를 포함 할 수 있습니다. 코드베이스의 모든 지점에서 모든 예외 처리를 변경하고 싶지는 않으므로 지금 높은 길을 택하고 원시 객체를 던지지 마십시오.


답변

std :: exception에서 파생 된 것을 던지는 것 외에도 익명의 임시를 던지고 참조로 잡아야합니다.

void Foo::Bar(){
  if(!QueryPerformanceTimer(&m_baz)){
    throw std::string("it's the end of the world!");
  }
}

void Foo:Caller(){
  try{
    this->Bar();// should throw
  }catch(std::string& caught){ // not quite sure the syntax is ok here...
    std::cout<<"Got "<<caught<<std::endl;
  }
}
  • 컴파일러가 던지는 객체의 수명을 다룰 수 있도록 익명의 임시를 던져야합니다. 힙에서 새로운 것을 던지면 다른 사람이이를 해제해야합니다.
  • 객체 슬라이싱을 방지하려면 참조를 잡아야합니다.

.

자세한 내용은 Meyer의 “Effective C ++-3 판”을 참조하거나 https://www.securecoding.cert.org/…/ERR02-A.+Throw+anonymous+temporaries+and+catch+by+reference를 방문 하십시오.


답변

C ++에서 예외를 발생시키는 가장 간단한 방법 :

#include <iostream>
using namespace std;
void purturb(){
    throw "Cannot purturb at this time.";
}
int main() {
    try{
        purturb();
    }
    catch(const char* msg){
        cout << "We caught a message: " << msg << endl;
    }
    cout << "done";
    return 0;
}

이것은 다음을 인쇄합니다.

We caught a message: Cannot purturb at this time.
done

throw 된 예외를 포착하면 예외가 포함되고 프로그램이 계속됩니다. 예외를 포착하지 않으면 프로그램이 존재하고 다음을 인쇄합니다.

This application has requested the Runtime to terminate it in an unusual way. Please contact the application's support team for more information.


답변

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

사용 std::nested_exceptionstd::throw_with_nested

제 생각에 이것을 사용하면 더 깨끗한 예외 디자인이 가능하고 예외 클래스 계층을 만들 필요가 없습니다.

이를 통해 디버거 나 번거로운 로깅없이 코드 내부의 예외에 대한 역 추적얻을 수 있습니다 . StackOverflow herehere 에 설명되어 있으며 중첩 된 예외를 다시 발생시키는 적절한 예외 처리기를 작성하는 방법 에 대해 설명합니다 .

파생 된 예외 클래스를 사용하여이 작업을 수행 할 수 있으므로 이러한 역 추적에 많은 정보를 추가 할 수 있습니다! 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"