C ++에서 오류 처리를위한 try-catch 또는 ifs 40, 1.0f, 1.0f,

예외는 게임 엔진 디자인에 널리 사용됩니까, 아니면 순수한 if 문을 사용하는 것이 더 바람직합니까? 예를 들면 다음과 같습니다.

try {
    m_fpsTextId = m_statistics->createText( "FPS: 0", 16, 20, 20, 1.0f, 1.0f, 1.0f );
    m_cpuTextId = m_statistics->createText( "CPU: 0%", 16, 20, 40, 1.0f, 1.0f, 1.0f );
    m_frameTimeTextId = m_statistics->createText( "Frame time: 0", 20, 20, 60, 1.0f, 1.0f, 1.0f );
    m_mouseCoordTextId = m_statistics->createText( "Mouse: (0, 0)", 20, 20, 80, 1.0f, 1.0f, 1.0f );
    m_cameraPosTextId = m_statistics->createText( "Camera pos: (0, 0, 0)", 40, 20, 100, 1.0f, 1.0f, 1.0f );
    m_cameraRotTextId = m_statistics->createText( "Camera rot: (0, 0, 0)", 40, 20, 120, 1.0f, 1.0f, 1.0f );
} catch ... {
    // some info about error
}

그리고 ifs와 함께 :

m_fpsTextId = m_statistics->createText( "FPS: 0", 16, 20, 20, 1.0f, 1.0f, 1.0f );
if( m_fpsTextId == -1 ) {
    // show error
}
m_cpuTextId = m_statistics->createText( "CPU: 0%", 16, 20, 40, 1.0f, 1.0f, 1.0f );
if( m_cpuTextId == -1 ) {
    // show error
}
m_frameTimeTextId = m_statistics->createText( "Frame time: 0", 20, 20, 60, 1.0f, 1.0f, 1.0f );
if( m_frameTimeTextId == -1 ) {
    // show error
}
m_mouseCoordTextId = m_statistics->createText( "Mouse: (0, 0)", 20, 20, 80, 1.0f, 1.0f, 1.0f );
if( m_mouseCoordTextId == -1 ) {
    // show error
}
m_cameraPosTextId = m_statistics->createText( "Camera pos: (0, 0, 0)", 40, 20, 100, 1.0f, 1.0f, 1.0f );
if( m_cameraPosTextId == -1 ) {
    // show error
}
m_cameraRotTextId = m_statistics->createText( "Camera rot: (0, 0, 0)", 40, 20, 120, 1.0f, 1.0f, 1.0f );
if( m_cameraRotTextId == -1 ) {
    // show error
}

예외는 ifs보다 약간 느리다는 것을 들었고 if-checking 방법과 예외를 혼합해서는 안됩니다. 그러나 예외적으로 모든 initialize () 메소드 또는 유사한 것 후에 ifs 톤보다 더 읽기 쉬운 코드가 있지만 때로는 내 의견으로는 하나의 메소드에 비해 너무 무겁습니다. 그들은 게임 개발에 좋습니까, 아니면 간단한 if를 사용하는 것이 더 좋습니까?



답변

짧은 대답 : Niklas Frykholm의 Sensible Error Handling 1 , Sensible Error Handling 2Sensible Error Handling 3 을 읽으십시오 . 실제로, 블로그에있는 동안 기사를 모두 읽으십시오. 내가 모든 것에 동의한다고 말하지는 않지만 대부분 금입니다.

예외를 사용하지 마십시오. 많은 이유가 있습니다. 나는 주요한 것들을 열거 할 것이다.

최신 컴파일러에서는 상당히 최소화되었지만 실제로 느려질 수 있습니다. 일부 컴파일러는 실제로 예외를 트리거하지 않는 코드 경로에 대해 “제로 오버 헤드 예외 없음”을 지원합니다 (예외 처리에 필요한 추가 데이터가 여전히 있기 때문에 실행 파일 / dll 크기가 부풀어 오름). 그러나 결과는 예외를 사용하는 것이 느리고 성능에 중요한 코드 경로에서는 예외를 피해야한다는 것입니다. 컴파일러에 따라 전혀 활성화하면 오버 헤드가 추가 될 수 있습니다. 대부분의 경우 항상 코드 크기를 크게 늘려 오늘날 하드웨어의 성능에 심각한 영향을 줄 수 있습니다.

예외는 코드를 훨씬 더 취약 하게 만듭니다 . 기본적으로 예외 안전 코드와 예외 안전하지 않은 코드를 작성하는 데 어려움이 차트에 표시되는 악명 높은 그래픽 (지금 슬프게도 찾을 수 없음)이 있으며, 전자는 상당히 큰 막대입니다. 예외 작은 개는 많은, 많은 단지가 있습니다 많은 코드를 작성하는 방법을 보이는 예외 안전하지만 정말 아니다는. 전체 C ++ 11위원회 조차도 이것에 대해 다루었 고 std :: unique_ptr을 올바르게 사용하기위한 중요한 도우미 함수를 추가하는 것을 잊어 버렸습니다. 이러한 도우미 함수조차도 사용하지 않는 것보다 더 많은 타이핑이 필요하며 대부분의 프로그래머는 그렇지 않은 경우 무엇이 잘못되었는지조차 깨닫지 못합니다.

보다 구체적으로 게임 산업에서 일부 콘솔의 공급 업체 제공 컴파일러 / 런타임은 예외를 완전히 지원하지 않거나 전혀 지원하지도 않습니다. 코드에서 예외를 사용하는 경우에도 여전히이 시대에 코드를 새로운 플랫폼으로 이식하기 위해 코드의 일부를 다시 작성해야 할 수도 있습니다. (콘솔이 출시 된 후 7 년 동안 변경되었는지 확실하지 않다; 우리는 예외를 사용하지 않고 컴파일러 설정에서도 예외를 비활성화했기 때문에 내가 말한 사람이 최근에 확인한 적이 있다는 것을 모른다.)

일반적인 사고 방식은 매우 분명합니다. 예외적 인 상황 에서는 예외를 사용하십시오 . 당신의 프로그램이 “어떻게해야할지 모르겠다. 다른 누군가가 뭘할지 모르겠다. 그래서 예외를 던지고 어떤 일이 일어나는지 볼 것이다.” 다른 옵션이 의미가 없을 때 사용하십시오. 적절한 스마트 핸들 사용을 망쳐 서 실수로 약간의 메모리가 누출되거나 리소스를 정리하지 못하는 경우 걱정하지 않을 때 사용하십시오. 다른 모든 경우에는 사용하지 마십시오.

예제와 같은 코드와 관련하여 문제를 해결하는 몇 가지 다른 방법이 있습니다. 간단한 예에서 가장 이상적인 것은 아니지만 더 강력한 방법 중 하나는 모나드 오류 유형에 의존하는 것입니다. 즉, createText ()는 정수가 아닌 사용자 정의 핸들 유형을 리턴 할 수 있습니다. 이 핸들 유형에는 텍스트를 업데이트하거나 제어하기위한 접근자가 있습니다. 핸들이 오류 상태 (createText ()가 실패했기 때문에)에 놓이면 핸들에 대한 추가 호출은 자동으로 실패합니다. 핸들을 쿼리하여 오류가 있는지 확인하고, 그렇다면 오류가 무엇인지 확인할 수 있습니다. 이 방법은 다른 옵션보다 오버 헤드가 많지만 상당히 견고합니다. 프로덕션에서 단일 작업이 실패 할 수 있지만 실패 / 불가 / 실적이없는 상황에서 긴 작업 문자열을 수행해야하는 경우에 사용하십시오.

모나드 오류 처리를 구현하는 대안은 사용자 정의 핸들 객체를 사용하는 대신 컨텍스트 객체의 메소드가 유효하지 않은 핸들 ID를 정상적으로 처리하도록하는 것입니다. 예를 들어, createText ()가 실패했을 때 -1을 반환하면, 그 핸들 중 하나를 취하는 m_statistics에 대한 다른 호출은 -1이 전달되면 정상적으로 종료되어야합니다.

실제로 오류가 발생한 함수에 오류 인쇄를 넣을 수도 있습니다. 귀하의 예에서 createText ()는 무엇이 잘못되었는지에 대한 자세한 정보를 가지고 있으므로 로그에 더 의미있는 오류를 덤프 할 수 있습니다. 이 경우 오류 처리 / 인쇄를 발신자에게 푸시하는 것이 별 도움이되지 않습니다. 호출자가 처리를 사용자 정의해야하거나 종속성 주입을 사용해야 할 때 수행하십시오. 오류가 기록 될 때마다 팝업 할 수있는 게임 내 콘솔을 사용하는 것이 좋습니다.

통계 시스템에 텍스트 블롭을 생성하는 간단한 동작과 같이 정상적인 환경에서 실패하지 않을 것으로 예상되는 통화에 대한 최상의 옵션 (위의 링크 된 기사에 이미 나와 있음)은 기능 만 갖는 것입니다. 실패했습니다 (예제에서 createText) 중단하십시오. 무언가 완전히 손상되지 않은 경우 (예 : 사용자가 글꼴 데이터 파일을 삭제했거나 어떤 이유로 256MB의 메모리 만있는 경우 등) 프로덕션 텍스트에서 createText ()가 실패하지 않을 것이라고 합리적으로 확신 할 수 있습니다. 이러한 많은 경우에 실패가 발생했을 때해야 할 일조차 없습니다. 메모리가 부족합니까? 사용자에게 OOM 오류를 표시하는 멋진 GUI 패널을 작성하는 데 필요한 할당을 수행하지 못할 수도 있습니다. 글꼴이 없습니까? 사용자에게 오류를 표시하기 어렵게 만듭니다. 무슨 일이 있어도

(a) 오류를 로그 파일에 기록하고 (b) 일반 사용자 작업으로 인해 발생하지 않는 오류에 대해서만 오류가 발생하는 한 충돌은 아주 좋습니다.

가용성이 중요하고 워치 독 모니터링이 충분하지 않지만 게임 클라이언트 개발 과는 다른 많은 서버 응용 프로그램에 대해 전혀 같은 말을하지 않습니다 . 다른 언어의 예외 처리 기능은 관리되는 환경이므로 C ++의 예외 안전 문제가 모두 없기 때문에 C ++처럼 물지 않는 경향이 있으므로 C / C ++를 사용하지 않는 것이 좋습니다. 서버가 게임 클라이언트와 같은 최소 지연 시간 보장보다 병렬 처리 및 처리량에 더 집중하는 경향이 있기 때문에 성능 문제도 완화됩니다. 예를 들어 C #으로 작성된 슈팅 게임 등을위한 액션 게임 서버조차도 FPS 클라이언트가하는 것처럼 하드웨어를 한계까지 밀기 어렵 기 때문에 C #으로 작성할 때 매우 잘 작동 할 수 있습니다.


답변

도널드 크 누스 자신의 오래된 지혜는 다음과 같습니다.

“우리는 시간의 약 97 %라는 작은 비 효율성을 잊어야합니다. 조기 최적화는 모든 악의 근원입니다.”

이 포스터를 큰 포스터로 인쇄하고 진지한 프로그래밍 작업을 수행하는 모든 곳에서 행 아웃하십시오.

그래서 심지어 경우 시도 / 잡기가 조금 느린 나는 기본적으로 그것을 사용합니다 :

  • 코드는 가능한 한 읽기 쉽고 이해하기 쉬워야합니다. 당신은 할 수 한 번 코드를 작성하지만 것이다 개선, 이해를 위해, 다른 코드를 디버깅하기 위해,이 코드를 디버깅 그것에게 더 많은 시간을 읽고 …

  • 성능에 대한 정확성. if / else를 올바르게 수행하는 것은 쉬운 일이 아닙니다. 귀하의 예에서는 하나의 오류가 표시 될 수 없지만 여러 오류가 표시되기 때문에 잘못 수행되었습니다. 캐스케이드 if / then / else를 사용해야합니다.

  • 일관되게 사용하기 쉬움 : Try / catch는 모든 라인에서 오류를 확인할 필요가없는 스타일을 수용합니다. 반면에 : 하나 다른 / IF 및 코드의 힘 사고의 혼란이 없습니다. 물론 재현 할 수없는 상황에서만.

그래서 마지막 요점 :

예외가 ifs보다 약간 느리다는 것을 들었습니다.

나는 약 15 년 전에 최근에 믿을만한 소식을들은 적이 없다고 들었습니다. 컴파일러가 개선되었거나 무엇이든 가능합니다.

요점은 다음과 같습니다. 조기 최적화를 수행하지 않습니다. 당신이 손에 코드가 일부 많이 사용되는 코드의 꽉 내부 루프는 것을 벤치 마크 증명할 수있는 경우에만 작업을 수행 하고 스타일 스위칭 성능을 크게 향상시킬 수 있음을 상당히 . 이것은 3 % 사례입니다.


답변

이미이 질문에 대한 훌륭한 답변이 있었지만 특정 경우 코드 가독성 및 오류 복구에 대한 생각을 추가하고 싶습니다.

코드가 실제로 다음과 같이 보일 수 있다고 생각합니다.

m_fpsTextId = m_statistics->createText( "FPS: 0", 16, 20, 20, 1.0f, 1.0f, 1.0f );
m_cpuTextId = m_statistics->createText( "CPU: 0%", 16, 20, 40, 1.0f, 1.0f, 1.0f );
m_frameTimeTextId = m_statistics->createText( "Frame time: 0", 20, 20, 60, 1.0f, 1.0f, 1.0f );
m_mouseCoordTextId = m_statistics->createText( "Mouse: (0, 0)", 20, 20, 80, 1.0f, 1.0f, 1.0f );
m_cameraPosTextId = m_statistics->createText( "Camera pos: (0, 0, 0)", 40, 20, 100, 1.0f, 1.0f, 1.0f );
m_cameraRotTextId = m_statistics->createText( "Camera rot: (0, 0, 0)", 40, 20, 120, 1.0f, 1.0f, 1.0f );

예외도없고 if도 없습니다. 오류보고는에서 수행 할 수 있습니다 createText. 그리고 createText나머지 코드도 마찬가지로 작동하도록 반환 값을 확인할 필요가없는 기본 텍스처 ID를 반환 할 수 있습니다.