새로운 std :: exception을 던져 std :: exception을 던져


113

몇 가지 코드를 보면서 우연히 발견했습니다.

throw /*-->*/new std::exception ("//...

그리고 나는 항상 당신이 필요하지 않거나 new여기에서 사용해서는 안된다고 생각했습니다 .
올바른 방법은 무엇이며, 차이가 있다면 둘 다 괜찮습니까?

내가 볼 수있는 BTW는 PowerShell 부스트 라이브러리를 사용하여 throw new.

추신 또한 사용하는 일부 CLI 코드를 찾았습니다 throw gcnew. 그 확인은?


1
throw gcnew예를 들어 유용 할 것이라고 생각 합니다. 관리 코드에서 예외를 포착하려는 경우. 누군가 나를 고칠 수 있습니까?
jpalecek 2012-06-08

1
.Net은 포인터로 예외를 처리하므로 gcnew를 던지는 것이 옳은 일입니다.
Sebastian Redl 2012-06-08

1
@SebastianRedl .Net "포인터"가 모호 할 수 있습니까? gcnew는 확실히 그렇지 않습니다. System::Exception일반적으로 가비지 수집 된 힙의 관리 대상 개체에 대한 참조입니다. 나는 항상 슬로우했습니다 gcnew과 함께 붙 잡았다 System::Exception ^. 물론 finallyC ++ / CLI에서도 항상 사용 하지만 동일한 try블록 에서 C ++ 예외와 자주 혼합되지는 않지만 그 이유는 확실하지 않습니다.

답변:


89

예외를 throw하고 catch하는 일반적인 방법은 예외 개체를 throw하고 참조 (일반적으로 const참조) 로 포착하는 것 입니다. C ++ 언어를 사용하려면 컴파일러가 예외 개체를 생성하고 적절한 시간에 적절하게 정리하기 위해 적절한 코드를 생성해야합니다.

동적으로 할당 된 개체에 대한 포인터를 던지는 것은 결코 좋은 생각이 아닙니다. 예외는 오류 상황에서보다 강력한 코드를 작성할 수 있도록합니다. 일반적인 방식으로 예외 객체를 던지면 올바른 유형을 명명하는 catch 절에 의해 포착 catch (...)되는지, 다시 던 졌는지 여부에 관계없이 적절한 시간에 올바르게 파괴되는지 확인할 수 있습니다. (아무것도 잡히지 않는 유일한 예외는 당신이 그것을 보는 방법에 관계없이 이것은 복구 불가능한 상황입니다.)

동적으로 할당 된 객체에 대한 포인터를 던지면 예외를 던지고 싶은 지점에서 호출 스택이 어떤 모양이든간에 올바른 포인터 유형을 명명하고 적절한 delete호출 이있는 catch 블록이 있는지 확인해야합니다 . catch (...)해당 블록이 예외를 다시 던지고 예외를 올바르게 처리하는 다른 catch 블록에 의해 포착되지 않는 한 예외를 포착해서는 안됩니다 .

사실상 이것은 강력한 코드를 더 쉽게 작성하고 모든 상황에서 올바른 코드를 작성하는 것을 매우 어렵게 만드는 예외 처리 기능을 사용했음을 의미합니다. 이것은이 기능을 기대하지 않는 클라이언트 코드에 대한 라이브러리 코드로 작동하는 것이 거의 불가능하다는 문제를 제쳐두고 있습니다.


1
"예외 개체 던지기"스택 또는 내 친구 힙? 스택 또는 힙? (어딘가에서 나쁜 글로벌 예제를보고 있었을 것입니다.) 오 그리고 스택이라면 적절한 범위는 무엇입니까?

@ebyrob : 당신이 무엇에 대해 물어보고 있는지 잘 모르겠지만 여기에 대답 할 수있는 예외 개체의 저장 및 / 또는 수명에 대해 알고 싶은 것처럼 들립니다 . 그렇지 않다면 별도의 질문을하는 것이 좋습니다.
CB Bailey

31

new예외를 던질 때 사용할 필요가 없습니다 .

그냥 써:

throw yourexception(yourmessage);

다음과 같이 잡으십시오.

catch(yourexception const & e)
{
      //your code (probably logging related code)
}

주의 yourexception에서 파생한다 std::exception직접 또는 간접적으로.


7
왜? 왜 사용하지 new않습니까? 왜 파생 yourexception에서 std::exception?
Walter

내가 게으 르면 (종종 Waaay) 왜 작동하지 throw std::exception;않습니까? g ++가 컴파일하지 않는 것 같습니다 ...

7
@ebyrob : std::exception유형입니다, 당신은 던질 수없는 유형의 당신은 던져진에, 한 객체 . 따라서 구문은 다음과 같아야합니다 throw std::exception();. 컴파일됩니다. 이제 그것이 얼마나 좋은지 완전히 다른 질문입니다.
Nawaz

22

던지기는 new std::exception호출 사이트가를 잡을 것으로 예상되는 경우 올바른 std::exception*. 그러나 아무도 예외에 대한 포인터를 잡을 것으로 기대하지 않습니다. 그것이 당신의 함수가하는 일을 문서화하고 사람들이 문서를 읽더라도, 그들은 여전히 ​​잊고 std::exception객체에 대한 참조를 잡으려고 시도 할 수 있습니다.


27
Throwing new std::exception은 호출 사이트가 포인터를 잡을 것으로 예상하고 할당 예외의 관리를 인수 할 것으로 예상하는 경우에만 정확하며 명시 적으로 catch하지 않는 무언가에 의해 함수가 호출되는 경우는 없습니다. 올바른 포인터 ( catch(...)또는 전혀 처리하지 않음) 그렇지 않으면 객체 누출이 발생합니다. 요컨대, 이것은 "never"로 근사 할 수 있습니다.
CB Bailey

이 답변이 어떻게 받아 들여 졌는지 궁금합니다. 정답 인 @CharlesBailey의 의견 입니다.
John Dibling

@John : 그것도 내 마음을 넘어 섰다. 그러나 나는 원투 펀치가 건조한 요약을 제공하는 데 좋은 효과가 있다고 생각하며 Charles는 사람들이 올바르게 처리하는 것을 잊기 쉬운 다양한 방법을 재미있게 확장합니다. 그래도 찬성 댓글에서 평판을 얻지 못해서 안타깝습니다.

Charles는 그의 대답을 제공하지 않았고,이 A는 (다른 것과는 달리) A와 주석 모두에 설명이 있습니다.
NoSenseEtAl 2012-06-08

9

C ++ FAQ에는 이에 대한 좋은 토론이 있습니다.

  1. https://isocpp.org/wiki/faq/exceptions#what-to-catch
  2. https://isocpp.org/wiki/faq/exceptions#catch-by-ptr-in-mfc

기본적으로 "그렇게하지 않을 이유가없는 한 참조로 잡으십시오. 값으로 잡는 것을 피하십시오. 그렇게하면 복사본이 만들어지고 복사본이 던져진 것과 다른 동작을 할 수 있기 때문입니다. 아주 특별한 상황에서만 포인터로 잡아야합니다. "


2
평소와 같이 FAQ는 잘못된 단어입니다. 값이나 참조로 잡을 수 있습니다. 포인터는 값 (값 또는 참조로 포착) 일뿐입니다. 유형이 기억 A유형과 구별되는 A*내가 할 경우, 그래서 throw A()내가 함께 잡을 수없는 catch(A* e)완전히 다른 유형 때문이다.
Martin York

이 링크는 이제 끊어졌습니다.
stephenspann

1
내가 링크 @spanndemic 고정
user1202136

1

new 연산자는 예외가 발생하지 않을 것이라고 보장 할 수 없습니다. 이러한 이유로 "유효한"(의도 된) 예외를 발생시키기 위해이를 사용하면 충돌하지 않을 것이라고 보장 할 수없는 코드가 생성됩니다. 한 번에 하나의 예외 만있을 수 있고 프로그램이 예외를 잡기 전에 두 개를 던지려고하기 때문에 구현이 할 수있는 가장 좋은 방법은 std :: terminate를 호출하여 프로그램을 즉시 중단하는 것입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.