2010-07-27 3 views
9

좀 더 적절한 질문이라고 생각해서 약간의 제목을 변경했습니다.C++,이 goto 문이 보증되어 있습니까?

리팩터링 하시겠습니까 (goto의 합법적 인 사용처럼 보입니까)? go 명령문을 제거하려면 다음 코드를 어떻게 리팩토링합니까?

#ifdef HAVE_GPU 
      // attempt to use GPU device 
      if (data.device) { 
       try { 
        Integral::Gpu eri(S, R, Q, block.shell()); 
        eri(basis.centers(), quartets, data.device); 
       } 
       // if GPU fails, propagate to cpu 
       catch(std::exception) { goto done; } 
       data.device += size; 
       host_index.extend(block_index); 
       block_index.data.clear(); 
      done: ; 
      } 
#endif 

if (data.device) { 
    try { 
     ... 
    } 
    catch(const std::exception&) { goto done; } 
    ... // more things which should not be caught 
done: ; 
} 

완전한 문을 사용하면

대부분의 선호도를 본 후, 나는 플래그와 함께 가기로 결정하지만, 씨 뉴욕의 의견에 감사드립니다.

감사합니다 모두

+2

블록에 무엇이 있는지 보지 않고 말하기는 어렵지만, 또 다른 가능성은 if 함수 내에서 코드를 이동하는 것입니다. (가독성을 향상시킬 수도 있고 아닐 수도 있습니다.) 그런 다음 일이 잘못되면 일찍 돌아올 수 있습니다. – GManNickG

+4

const 참조로 잡으십시오. –

+0

@GMan은 완전한 성명을 추가했습니다. 폐쇄가 없으므로 기능이 과도 할 수 있습니다. – Anycorn

답변

15
if (data.device) 
{ 
    bool status = true; 

    try 
    { 
     ... 
    } 
    catch(std::exception) 
    { 
     status = false; 
    } 

    if (status) 
    { 
    ... // more things which should not be caught 
    } 
} 
+0

은 다소 명백한 대답이 될 수 있지만 선호하는 것은 무엇입니까? 상태 또는 고토? – Anycorn

+1

@aaa : 내가 반기를 들지 않는 반고견 인 이래로 나는 최고의 사람이 아니기를 바랍니다. :-) 오늘 아침에 나는 "당신이 goto없이 어떻게 할 것인가?"라는 질문에 답하기 위해 downvoted되었습니다. 그러나 나의 이유는 키워드에 대한 싫어하는 것보다 확장 성 및 직교성과 더 관련이 있습니다. –

+5

사람들은 왜 고토를 피하기 위해 새로운 변수와 가지를 도입해야한다고 주장합니까? "유해한 것으로 간주되는"서류의 쿨 에이드를 마시는 것을 중지하십시오. 실제로는 종이를 읽으십시오. 다이 ㅅ 스 트라는 결코 사용하지 않는 것을 보지 않을 것입니다. 실제로 당신이하고있는 일에 대한 비판적인 사고를하십시오. 코드에 상태와 브랜치를 더 추가하여 "goto"를 사용하지 않았습니다. " –

2

if 외부에서 예외를 catch 할 수 있습니까?

+0

다른 논리는 매우 못 생기므로 – Anycorn

3
if (data.device) { 
    bool ok = true; 
    try { 
     ... 
    } 
    catch(std::exception) { ok = false; } 

    if(ok) { 
     ... // more things which should not be caught 
    } 
} 
+0

이전 답변 중 하나에서 위와 동일한 대답. –

7

당신은 예외를 잡아 조건 블록 외부에서 처리 할 수있는 특정 예외를 다시 발생 할 수 있습니다.

// obviously you would want to name this appropriately... 
struct specific_exception : std::exception { }; 

try { 
    if (data.device) { 
     try { 
      // ... 
     } 
     catch(const std::exception&) { 
      throw specific_exception(); 
     } 

     // ... more things which should not be caught ... 
    } 
} 
catch (const specific_exception&) { 
    // handle exception 
} 
+1

감사합니다. 나는 그것에 대해 생각했지만 goto/flag보다 제 의견이 더 복잡합니다. – Anycorn

+0

@aaa : 내 의견으로는,이 옵션들 중 하나보다 훨씬 깨끗합니다. 'goto'는이 경우 완전히 보증되지 않습니다. 상태 플래그를 사용하면 하나의 코드 블록에 서로 다른 두 가지 오류보고 메커니즘 (상태 플래그 및 예외)이 혼합되어 복잡성이 크게 증가하고 코드에 대한 이유. –

+0

* goto의 의미는 무엇입니까/부당한 것입니까? 'goto'의 행동은 잘 정의되어 있으며, 나는 당신이 기대하는 것을 할 것인가, 그렇지 않을 것인가? 나는 bool check를 추가하는 것이 어쨌든 갈 방법이 아니라는 것에 동의한다. –

1

일부 플래그를 사용하고 조건문을 추가하는 것은 어떨까요?

int caught = 0; 
if (data.device) { 
    try { 
     /* ... */ 
    } catch (std::exception e) { caught = 1; } 
    if (!caught) { 
     // more stuff here 
    } 
    // done: ... 
} 
+5

'bool' 유형에 반대되는 것이 있습니까? –

8

첫 번째 : goto는 본질적으로 위험하지 않습니다. 당신의 코드에 "goto"라는 글자가없는 순수한 술을 리펙토링하는 것은 말도 안됩니다. 같은 것을 고토보다 깔끔하게 처리 할 수있는 것으로 리팩토링하는 것이 좋습니다. 나쁜 디자인을 더 나은 것으로 바꾸거나 고토 또는 교체를 필요로하지 않는 디자인으로 바꾸는 것도 좋습니다.

내가 말했듯이, 귀하의 코드는 마침내 발명 된 것과 같습니다. 너무 슬픈 C++에는 이와 같은 것이 없습니다 ... 그래서 가장 쉬운 해결책은 그것을 그대로 두는 것입니다.

+0

지옥 예! 가서 고토! 가라. 에! – Gianni

+3

불행하게도 finally()는 코드가 예외가 없을 때만 사용되므로 올바른 솔루션이 아닙니다. 마지막으로 예외가있을 때도 항상 실행되어야한다는 의미입니다. C#과 Java와 같은 언어에는 마침내 필요하지만 C++에는 필요하지 않습니다. 동일한 기술을 구현하는 데 더 좋은 기술이 있기 때문입니다. 나는 당신의 다른 모든 점에 동의하지만. 부러지지 않은 것을 고치지 마십시오. –

+1

'본래의'적절한 사용과 철자법에 대해 표결을하십시오. –

2

일부 조건에 따라 종료해야하는 코드가있는 경우 필자가 선호하는 구성은 "do {} while (0)"루프를 사용하고 적절한 경우 "중단"을 사용하는 것입니다. 나는 무엇이 붕괴하는지 모른다. 그래도 잡을 것입니다. "중단"이 작동하지 않으면 "goto"가 최선의 방법 일 수 있습니다.

+0

그것은 모든면에서'goto'보다 나쁩니다. – Thomas

+0

+1 그것도'goto'만큼 나쁘지 만, 여분의 변수를 추가하고 코드에 조건을 추가하는 것보다 낫습니다. 그리고 나는 이것들 중 하나가 새로운 예외 유형을 던지는 것보다 낫다고 생각합니다 ... 나는 여전히 'goto'를 선호하지만,이 대답은 다른 것보다 더 가치가 없습니다. :) –

1
catch(std::exception) { return; } 

트릭을 수행해야합니다. 나는 물론 done이 실제로 함수의 끝 부분에 있다고 가정합니다.

예외가 발생할 때 추가 코드를 실행해야하는 경우 상태를 반환하거나보다 적절한 추상화 수준의 예외를 throw합니다 (James의 대답 참조).

나는 같은 것을 상상 해요 : try 블록 내부의 추가 코드를 이동하지 왜

doStuff(...) { 
    bool gpuSuccess = doGPUStuff(...); 
    if (!gpuSuccess) { 
     doCPUStuff(...); 
    } 
} 
+0

그리고 함수의 모든 것을 건너 뜁니다. – GManNickG

+0

어떤 것이 옳은 일인지, 적어도 리팩터링 할 사람이있을 수 있습니다. –

+2

'done :'은 현재 함수의 끝이라고 생각하지 않습니다. GPU가 아닌 CPU를 사용하는 코드가 있습니다 (실패했거나 컴파일해야 함). –

4

?

#ifdef HAVE_GPU 
      // attempt to use GPU device 
      if (data.device) { 
       try { 
        Integral::Gpu eri(S, R, Q, block.shell()); 
        eri(basis.centers(), quartets, data.device); 
        data.device += size; 
        host_index.extend(block_index); 
        block_index.data.clear(); 
       } 
       // if GPU fails, propagate to cpu 
       catch(std::exception) { /* handle your exception */; } 
      } 
#endif 
+1

처음 두 줄에 던져 질 수있는 정격 브레이크 포인트가 포함되어 있다는 OP 코드가 명확 해졌습니다. 귀하의 예는 모든 예외를 삼킨 것입니다. 'host_index.extend()'는 이제 자동으로 실패 할 수 있습니다. –

+0

기본적으로 말하자면 가능한 한 try 블록 안에 최소한의 코드를 넣으시겠습니까? –

+0

그가 분명하게 말하면, 그것은 의문의 여지가 없다. catch 내에서 "예외 처리"라는 주석을 주목하십시오. 이 코드를 작성하는 것은 OP에게 달려 있습니다. –

4

을 나는이의 변형이 당신을 위해 일 것 같아요.

// attempt to use GPU device 
if (data.device) 
{ 
    try 
    { 
     Integral::Gpu eri(S, R, Q, block.shell()); 
     eri(basis.centers(), quartets, data.device); 

     data.device += size; 
     host_index.extend(block_index); 
     block_index.data.clear(); 
    } 
    catch (const std::bad_alloc&) 
    { 
     // this failure was not because 
     // of the GPU, let it propagate 
     throw; 
    } 
    catch(...) 
    { 
     // handle any other exceptions by 
     // knowing it was the GPU and we 
     // can fall back onto the CPU. 
    } 
} 

// do CPU 

는 GPU 라이브러리를 편집하고 모든 GPU 예외를 gpu_exception 같은 몇 가지 기본을 줄 수 있다면, 코드는 훨씬 간단하게 이러한 작업의 지옥, 내가 생각하는 경우

// attempt to use GPU device 
if (data.device) 
{ 
    try 
    { 
     Integral::Gpu eri(S, R, Q, block.shell()); 
     eri(basis.centers(), quartets, data.device); 

     data.device += size; 
     host_index.extend(block_index); 
     block_index.data.clear(); 
    } 
    catch (const gpu_exception&) 
    { 
     // handle GPU exceptions by 
     // doing nothing and falling 
     // back onto the CPU. 
    } 

    // all other exceptions, not being 
    // GPU caused, may propagate normally 
} 

// do CPU 

는 차선책이다 Steve's answer.

4

깃발을 조금씩 사용합니다. 나는 Amardeep보다 낫다고 생각합니다.

전체 지점 예외가 마지막 항목이 작동했는지 여부를 확인하지 않기 때문에 예외가 전파되었는지 여부를 나타내는 플래그보다 오히려 마지막 것이 작동했는지 여부를 나타내는 플래그보다 플래그를 사용합니다. 아이디어는 우리가 이것을 가지고 있다면, 모든 것이 작동하고 계속할 수 있도록 코드를 작성하는 것입니다.

#ifdef HAVE_GPU 
    // attempt to use GPU device 
    if (data.device) { 
     bool dont_catch = false; 
     try { 
      ... 
      dont_catch = true; 
      ... // more things which should not be caught 
     } catch (...) { 
      if (dont_catch) throw; 
     } 
    } 
#endif 
+0

오, 좋은 생각. :) – GManNickG

+1

@GMan : 변경된 사항 - 질문자의 코드와는 다른 행동이지만 물론 가치 대 참조 이상을 저장합니다 ;-) –

2

오전 뭔가 누락, 또는이 try 블록 내부의 catchdone: 라벨의 일부를 이동 동등하지 않을까요?

#ifdef HAVE_GPU 
      // attempt to use GPU device 
      if (data.device) { 
       try { 
        Integral::Gpu eri(S, R, Q, block.shell()); 
        eri(basis.centers(), quartets, data.device); 
        data.device += size; 
        host_index.extend(block_index); 
        block_index.data.clear(); 
       } 
       // if GPU fails, propagate to cpu 
       catch(std::exception) {} 
      } 
#endif 
+1

+1 : * 이것이 * OP가 원하는 작업 인 경우 가장 간단한 솔루션. –

+0

예, 뭔가 빠졌습니다. 이제 던지기 전에 try를 벗어난 것이 있다면 그 예외는 그냥 먹 힙니다. – GManNickG

1

그 자체의 기능/방법 (그 이후의 모든 것을 포함)으로 분해하고 return 키워드를 사용하십시오. 모든 변수가 소멸자를 가지거나 스택 할당 (또는 피할 수없는 경우 똑똑한 지적)되는 한 괜찮습니다. 나는 지속적인 플래그 검사보다는 조기 종료 함수/메소드에 대한 큰 팬이다. 예를 들어

:

void myFunc() 
{ 
    String mystr("heya"); 
    try 
    { 
     couldThrow(mystr); 
    } 
    catch(MyException& ex) 
    { 
     return; // String mystr is freed upon returning 
    } 

    // Only execute here if no exceptions above 
    doStuff(); 
} 

이 방법이 잘못 어렵다

+0

동의. 그냥 함수에 넣고, 원할 때 돌아와서, 돌아와. – jalf

1

오늘에 눈살을 찌푸렸다되는 이유 고토 우리가이 멋진 일을 대신 "기능"이라고 가지고있다. GPU 코드를 자체 함수로 랩핑하십시오. 실패 할 경우 일찍 리턴 할 수 있습니다.

그런 다음 원래 함수에서 호출하십시오. 그들은 아마도 (data, host_indexblock_index, 그것은 모양) 몇 가지 변수를 공유해야하기 때문에

는 클래스에 넣어, 그것의 두 가지 기능 회원을합니다.

void RunOnGpu(){ 
     // attempt to use GPU device 
     if (data.device) { 
      try { 
       Integral::Gpu eri(S, R, Q, block.shell()); 
       eri(basis.centers(), quartets, data.device); 
      } 
      // if GPU fails, propagate to cpu 
      catch(std::exception) { return; } 
      data.device += size; 
      host_index.extend(block_index); 
      block_index.data.clear();  
} 
void DoStuff() { 
#ifdef HAVE_GPU 
    RunOnGpu(); 
#endif 
} 
관련 문제