문제

을하고있 Java 에 대한 수 년 동안 그렇게되지 않았 추적 C++.가 마지막으로 절에 추가 되었습니다 C++예외 처리에 있어?

이 선호하는 관용을 모방하는 자바의 try/마지막으로?

또한 귀찮게 하는 C++없는 궁극적인 슈퍼 유형에 대한 모든 가능한 예외가 될 수 있는 던져 같이 Java 의 Throwable 클래스입니다.

내가 쓸 수 있습니다:

try {
  // do something
} catch(...) {
  // alas, can't examine the exception
  // can only do cleanup code and perhaps rethrow, ala:
  throw;
}

부록 편집:

결국 받아들이 대답하는 가장까지 투표,즉,사용 소멸자 할 cleanup.물론, 내 자신의 의견,그것은 분명 I 하지 않는 완전히 동의합니다.그러나,C++은 무엇이며 그래서 응용 프로그램 노력에 마음,내가 더 많거나 적은 노력 을 준수하는 일반적인 커뮤니티 습니다.나는 사용 템플릿 클래스 포장 리소스가 없는 클래스 소멸자(즉,C 라이브러리 리소스),따라서 수여서 그들을 소멸자는 의미입니다.

새로운 부록 편집:

Hmm,대 마지막으로 다음 폐쇄 기능까?폐쇄와 결합된 ScopeGuard 방법(중 하나를 참조하십시오 에 대한 답변을 아래에)것입하는 방법 을 달성 정리로 임의 작업 및 액세 정리 코드 범위의 외부 상황.정리 할 수 있에 관용구 패션에서 보이는 루비 프로그래밍을 공급하 블록을 정리할 때는 리소스가 열립니다.지 마감 특징되는 것으로 간주한 C++?

도움이 되었습니까?

해결책

소멸자를 효과적으로 사용함으로써. 예외가 시도 블록에 던져지면, 그 안에 생성 된 물체는 즉시 파괴됩니다 (따라서 소멸자라고 함).

이것은 객체의 최종화기가 언제 호출 될지 모르는 Java와 다릅니다.

업데이트: 말의 입에서 바로 : C ++가 "마지막으로"구성을 제공하지 않는 이유는 무엇입니까?

다른 팁

내 $ .02. C# 및 Java와 같은 관리 언어로 수년간 프로그래밍 해 왔지만 속도 목적으로 C ++로 전환해야했습니다. 처음에 나는 헤더 파일에 메소드 서명을 두 번 쓸 방법을 믿을 수 없었고, CPP 파일에서 어떻게 블록이 없는지가 마음에 들지 않았으며, 쓰레기 수집이 어디에서나 메모리 누출을 추적하는 것을 의미했습니다. 세상에 전혀 좋아하지 않았어요!

그러나 내가 말했듯이 C ++를 사용해야했습니다. 그래서 나는 그것을 진지하게 배워야했고, 이제 나는 마침내 Raii와 같은 모든 프로그래밍 관용구를 이해했고 언어의 모든 미묘함을 얻었습니다. 시간이 걸렸지 만 이제는 C# 또는 Java와 비교되는 언어와 얼마나 다른지 알 수 있습니다.

요즘 나는 C ++가 최고의 언어라고 생각합니다! 그렇습니다. 때때로 내가 'Chaff'라고 부르는 것이 조금 더 있다는 것을 이해할 수 있지만 (쓸 필요가없는 것 같습니다) 실제로 언어를 진지하게 사용한 후에는 완전히 마음이 바뀌 었습니다.

나는 항상 메모리 누출을 가졌습니다. 코드의 분리를 미워했기 때문에 모든 코드를 .H 파일에 작성했는데 왜 그렇게할지 이해할 수 없었습니다! 그리고 나는 항상 어리석은 순환으로 끝나고 종속성을 포함하고 더 많은 힙을 포함했습니다. 나는 C# 또는 Java에 정말로 매달렸다. C ++는 큰 발걸음이었다. 요즘 나는 그것을 얻는다. 나는 메모리 누출이 거의없고 인터페이스와 구현의 분리를 즐기며 더 이상 사이클 종속성에 문제가 없습니다.

그리고 나는 마침내 블록을 놓치지 않습니다. 솔직히 말해서, 내 의견은 캐치 블록에 반복적 인 정리 액션을 작성하는 것에 대해 이야기하는이 C ++ 프로그래머는 C ++ 프로그래머가 나쁜 것처럼 나에게 들린다는 것입니다. 내 말은,이 스레드의 다른 C ++ 프로그래머처럼 보이지는 않습니다. Raii는 실제로 마침내 중복을 만들어 내고, 무엇이든 더 적은 작업입니다. 당신은 하나의 소멸자를 쓰고 마침내 다른 것을 쓸 필요가 없습니다! 적어도 그 유형에 대해.

존경심을 가지고, 내가 생각하는 것은 당신이 내가했던 것처럼 지금 Java에 익숙하다는 것입니다.

C ++의 대답은 RAII입니다 : 물체의 소멸자는 범위를 벗어날 때 실행됩니다. 귀환에 의한 것, 예외 또는 그 밖의. 다른 곳에서 예외를 처리하는 경우, 호출 기능에서 핸들러까지의 모든 객체가 소멸자에게 전화를 걸어 올바르게 파괴 될 수 있습니다. 그들은 당신을 위해 정리할 것입니다.

읽다 http://en.wikipedia.org/wiki/resource_acquisition_is_initialization

마침내 C ++에 추가되지 않았으며, 추가 될 가능성이 없습니다.

C ++가 생성자/파괴자를 사용하는 방식은 결국 불필요하게 필요합니다.
Catch (...)를 사용하여 정리하는 경우 C ++를 제대로 사용하지 않습니다. 정리 코드는 모두 소멸자에 있어야합니다.

C ++는 STD :: 예외를 사용하는 것이 필요하지는 않지만.
개발자가 특정 클래스에서 도출하여 예외를 사용하도록 강요하는 것은 C ++의 간단한 철학에 위배됩니다. 또한 모든 클래스가 객체에서 파생되도록 요구하지 않는 이유.

읽다: C ++가 '마지막으로'블록을 지원합니까? (그리고 내가 계속 듣고있는이 'raii'는 무엇입니까?)

마지막으로 사용하는 것은 청소를 수행하는 것보다 더 많은 오류가 발생합니다.
이는 객체 사용자가 클래스의 디자이너/구현자가 아닌 정리를하도록 강요하기 때문입니다.

Ok,I 을 추가해야에 응답하는 포인트는 당신에 별도의 응답 post:(그것은 훨씬 더 편리한다면 편집이로 원래의 질문에,그래서 그것을 끝나지 않는 최대 바닥에 대한 답변을니다.

모든 정리가 항상 수행 소멸자는 다음에는 필요 없을 것 모든 정리 코드에서는 캐치 블록 아직 C++는 캐치 블록 정리 작업입니다.실제로 그것은 는 블록을 위한 캐치(...)는 만 정리 작업 (물론,확실히 얻을 수 없습니다 어떤 예외는 정보를 무엇이든 기록).

catch 는 완전히 별도의 목적,자바 프로그래머로서 알고 있어야 합니다.마지막으로 절은"무조건적인"정리 작업입니다.하는 방법에 상관없이 블록이 종료되,이를 할 수 있어야 합니다.Catch 은 조건부 정리입니다.이 형식의 예외가 발생하고,우리가 수행해야 할 몇 가지 추가 작업입니다.

정리에 마지막으로 블록 을 얻을 수 있는지 여부를 했 발생한 예외 또는 무엇을 하고 일어날 때 정리 코드가 존재합니다.

정말입니까?우리가 원하는 경우 그것을 일에 대한 이 유형(예를 들어,우리는 항상 닫으려는 데이터베이스 연결할 때 우리는 그것으로 완료),다음을 왜 우리가 그것을 정의한다 ?에 입력까?데이터베이스 연결을 닫을 자체보다는 try/마지막으로 주위의 모든 단 하나 그것의 사용?

는 시점에 소멸자입니다.그들은 보증하는 각 유형의 자신의 정리,매 시간 사용하지 않고,발신자를 생각합니다.

C++개발자에서 하루에 하나가되었습 시달리고 하는 것으로 반복합 정리 에 표시되는 작업 catch 블록 코드의 흐름에 따라 발생하는 성공적인 출구에서도 블록입니다.Java,C#프로그래머는 단지 그것을 후에 마지막으로 차단합니다.

No.C++프로그래머지 않에 시달리고있다.C 프로그래머다.C 프로그래머는 것을 깨달았 c++했다 클래스라는 자신 C++프로그래머다.

내 프로그램에서는 C++과 C#매일,그리고 나는 느낌이 나에 시달리고 C#'s ridiculous 주장하는 나 제공해야 합니다 마지막으로 절(나 using 블록이)모든 데이터베이스를 사용하여 연결 또는 다른 뭔가가는 청소해야 합니다.

C++할 수 있습을 지정하고 한번에 모든 것을 때마다"우리는 이 형식,그것은 이러한 작업을 수행하".내가 위험하지 않고 잊고 메모리를 해제합니다.내가 위험을 감수하지 않을 잊을 닫고 파일 핸들을 소켓 또는 데이터베이스 연결이 있습니다.기 때문에 메모리가 내 손잡이,소켓과 다른 데이터베이스에 연결 하십니다.

어떻게 그 이 될 것이 바람직하를 작성해야 중복 정리 코드를 사용할 때마다 종류?필요하신 경우에는 포장 유형이 있지 않기 때문에 소멸자 자체,당신은 간단한 두 가지 옵션이 있습니다:

  • 보에 대해 적절한 C++라이브러리 제공하는 이 소멸자(힌트:Boost)
  • 사용 부스트::shared_ptr 포장 및 공급자 정의 함수에서 런타임이 지정하는 정리를 수행 할 수 있습니다.

을 쓸 때 서버 응용 프로그램 소프트웨어 다음과 같이 Java EE 응용 프로그램 Glassfish,JBoss,etc., 할 을 잡을 수 있 로그인 예외 정보-반대로 보자 가을 바닥에 있습니다.나 더 빠 런타임과 비정상적인 원인 갑작스러운 종료 응용 프로그램의 서버입니다.그 이유는 그것은 매우 바람직한가 무엇보다 중요한 기본 클래스 가능한 예외는 아니다.C++는 이러한 클래스입니다.std::예외는 아니다.

행 C++이후 CFront 일 Java/C#의 대부분이다.가 분명하게 관리할 수 있는 엄청난 문화 격차에 어떻게 근본적으로 비슷한 것이 다가왔다.

No,코 C++.당신이 한 CFront,또는 C 클래스입니다.C++.가 큰 차이가 있습니다.종료를 호출하는 답변이 불구하고,당신이 뭔가를 배울 수 있습니하는 언어에 대한 생각을 알고 있었다.;)

청소 기능 자체는 완전히 절름발이입니다. 그들은 응집력이 낮으며, 그들이 일어날 때만 관련된 일련의 활동을 수행 할 것으로 예상됩니다. 그들은 실제로 무언가를하는 기능이 변경 될 때 내부를 수정해야한다는 점에서 높은 커플 링을 가지고 있습니다. 이 때문에 오류가 발생하기 쉽습니다.

시도 ... 마지막으로 구성은 정리 기능을위한 프레임 워크입니다. Lousy 코드를 작성하는 언어에 대한 언어에 대한 방법입니다. 또한, 동일한 정리 코드를 반복해서 쓰는 것이 장려되므로 건조 원칙을 손상시킵니다.

C ++ 방식은 이러한 목적으로 훨씬 바람직합니다. 자원의 정리 코드는 파괴자에서 정확하게 한 번 작성됩니다. 해당 리소스의 나머지 코드와 같은 장소에 있으므로 응집력이 좋습니다. 정리 코드를 관련없는 모듈로 넣을 필요는 없으므로 커플 링이 줄어 듭니다. 잘 설계 될 때 정확하게 한 번 작성됩니다.

또한 C ++ 방식은 훨씬 더 균일합니다. Smart Pointer 추가 기능을 갖춘 C ++는 모든 종류의 리소스를 동일한 방식으로 처리하는 반면 Java는 메모리를 잘 처리하고 다른 리소스를 릴리스 할 수있는 부적절한 구성을 제공합니다.

C ++에는 많은 문제가 있지만 이것은 그 중 하나가 아닙니다. Java가 C ++보다 더 나은 방법이 있지만 이것은 그 중 하나가 아닙니다.

Java는 시도 대신 Raii를 구현하는 방법으로 훨씬 나아질 것입니다.

모든 출시 가능한 리소스에 대해 래퍼 클래스를 정의하지 않아도 Scopeguard에 관심이있을 수 있습니다 (http://www.ddj.com/cpp/184403758)이를 통해 "클리너"를 즉시 생성 할 수 있습니다.

예를 들어:

FILE* fp = SomeExternalFunction();
// Will automatically call fclose(fp) when going out of scope
ScopeGuard file_guard = MakeGuard(fclose, fp);

마침내 올바르게 사용하는 것이 얼마나 어려운지의 예입니다.

두 파일을 열고 닫습니다.
파일이 올바르게 닫히도록 보장하려는 경우.
파일을 재사용 할 수 있으므로 GC를 기다리는 것은 옵션이 아닙니다.

C ++에서

void foo()
{
    std::ifstream    data("plop");
    std::ofstream    output("plep");

    // DO STUFF
    // Files closed auto-magically
}

소멸자는 없지만 결국 조항이있는 언어로.

void foo()
{
    File            data("plop");
    File            output("plep");

    try
    {
        // DO STUFF
    }
    finally
    {
        // Must guarantee that both files are closed.
        try {data.close();}  catch(Throwable e){/*Ignore*/}
        try {output.close();}catch(Throwable e){/*Ignore*/}
    }
}

이것은 간단한 예이며 이미 코드가 복잡 해지고 있습니다. 여기서 우리는 단순한 자원을 마샬링하려고 노력하고 있습니다. 그러나 관리 해야하는 자원의 수가 증가하고/또는 복잡성이 증가함에 따라 최종 블록의 사용이 예외가있을 때 올바르게 사용하기가 더 어려워지고 어렵습니다.

결국 올바른 사용에 대한 책임을 객체 사용자에게 최종적으로 움직입니다. C ++가 제공하는 생성자/소멸자 메커니즘을 사용하면 올바른 사용에 대한 책임을 클래스의 디자이너/구현 자에게 이동합니다. 디자이너가 수업 수준에서 한 번만 올바르게 수행하면됩니다 (다른 사용자가 다른 방식으로 올바르게 시도하지 않고).

C ++ 11을 사용하여 람다 표현, 최근에 다음 코드를 사용하기 시작했습니다. finally:

class FinallyGuard {
private:
  std::function<void()> f_;
public:
  FinallyGuard(std::function<void()> f) : f_(f) { }
  ~FinallyGuard() { f_(); }
};

void foo() {
  // Code before the try/finally goes here
  { // Open a new scope for the try/finally
    FinallyGuard signalEndGuard([&]{
      // Code for the finally block goes here
    });
    // Code for the try block goes here
  } // End scope, will call destructor of FinallyGuard
  // Code after the try/finally goes here
}

그만큼 FinallyGuard 호출 가능한 기능과 같은 인수, 선호하는 람다 표현식으로 구성되는 물체입니다. 소멸자가 호출 될 때까지 기능을 단순히 기억할 것입니다. 이는 정상 제어 흐름으로 인해 또는 예외 처리 중에 스택 풀기로 인해 객체가 범위를 벗어나는 경우입니다. 두 경우 모두 소멸자가 함수를 호출하여 해당 코드를 실행합니다.

코드를 작성해야한다는 것은 조금 이상합니다. finally ~ 전에 코드 try 블록이지만 그 외에는 실제로 진짜처럼 느껴집니다. try/finally Java에서. 나는 자신의 적절한 파괴자가있는 물체가 더 적절한 상황에 대해 이것을 남용해서는 안된다고 생각하지만,이 접근법보다 더 적합하다고 생각하는 경우가 있습니다. 나는 그러한 시나리오를 논의했다 이 질문.

내가 물건을 이해하는 한 std::function<void()> 포인터 간접 및 적어도 하나의 가상 함수 호출을 사용하여 수행합니다. 삭제를 입력하십시오, 그래서 a가있을 것입니다 성능 오버 헤드. 성능이 중요한 경우이 기술을 꽉 조이는 루프에서 사용하지 마십시오. 그러한 경우, 소멸자가 한 가지 일을하는 특수한 물체가 더 적절할 것입니다.

C ++ 소멸자가 만들어집니다 finally 불필요한. 정리 코드를 최종적으로 해당 파괴자로 이동시켜 동일한 효과를 얻을 수 있습니다.

나는 당신이 무엇의 요점을 놓치고 있다고 생각합니다 catch (...) 할수있다.

당신은 당신의 예에서 "아아, 예외를 조사 할 수 없다"고 말합니다. 글쎄, 당신은 예외 유형에 대한 정보가 없습니다. 당신은 그것이 다형성 유형인지조차 모르기 때문에 그것에 대해 어떤 종류의 참조를 가지고 있더라도 안전하게 시도 할 수 없었습니다. dynamic_cast.

당신이 무언가를 할 수있는 특정 예외 또는 예외 계층에 대해 알고 있다면, 이것은 유형이라는 이름의 설명이있는 캐치 블록을위한 장소입니다.

catch (...) C ++에서는 종종 유용하지 않습니다. 그것은 던지지 않도록 보장하거나 계약 된 특정 예외 만 던지는 장소에서 사용될 수 있습니다. 사용중인 경우 catch (...) 청소의 경우 코드가 강력하게 예외적이지 않을 가능성이 매우 높습니다.

다른 답변에서 언급했듯이 로컬 객체를 사용하여 리소스를 관리하는 경우 (RAII)는 놀랍고 깨달을 수 있습니다. 예외가 클라이언트 코드로 흘러 나오는 동시에 리소스 문제를 보장 할 수있는 클라이언트 코드로 출시되면서 시도 블록이 중복 될 수 있습니다.

원래 질문에 답하기 위해 블록 끝에서 실행하기 위해 코드 조각이 필요하거나 예외 또는 예외는 없다면 레시피가 될 것입니다.

class LocalFinallyReplacement {
    ~LocalFinallyReplacement() { /* Finally code goes here */ }
};
// ...
{ // some function...
    LocalFinallyReplacement lfr; // must be a named object

    // do something
}

우리가 완전히 멀리 할 수있는 방법에 주목하십시오 try, catch 그리고 throw.

"마지막으로"블록에서 액세스 할 수있는 시도 블록 외부에서 원래 선언 된 함수의 데이터가있는 경우,이를 도우미 클래스의 생성자에 추가하고 파괴자까지 저장해야 할 수도 있습니다. 그러나이 시점에서 나는 로컬 리소스 처리 객체의 설계를 변경하여 문제가 해결 될 수 있는지 심각하게 재고 할 것입니다.

완전하게 Offtopic이 아닙니다.

Java의 보일러 도금 DB 자원 정리

풍자 모드 : Java 관용구가 훌륭하지 않습니까?

나는 15 년 동안 C ++에서 많은 수업 디자인과 템플릿 래퍼 디자인을 수행했으며 소멸자 청소 측면에서 모든 C ++ 방식으로 수행했습니다. 그러나 모든 프로젝트는 또한 열린 IT와 함께 리소스를 제공 한 C 라이브러리의 사용과 관련이 있습니다. 시도/마침내는 그러한 자원이 완전히 강력한 방식으로 필요한 곳에 소비 될 수 있다는 것을 의미합니다. 그 상황을 프로그래밍하는 데 가장 적은 지루한 접근법. 일부 래퍼 파괴자에서 비웃지 않고도 해당 청소의 논리 중에 진행되는 다른 모든 상태를 다룰 수 있습니다.

Windows에서 C ++ 코딩의 대부분을 수행 했으므로 항상 그러한 상황에 대해 Microsoft의 __try/__을 사용할 수있었습니다. (구조화 된 예외 처리는 예외와 상호 작용할 수있는 강력한 능력을 가지고 있습니다.) 아아, C 언어는 휴대용 예외 처리 구성을 비준 한 것처럼 보이지 않습니다.

그래도 이상적인 솔루션은 아니 었습니다. 왜냐하면 두 스타일의 예외 스타일이 던져 질 수있는 시도 블록에서 C 및 C ++ 코드를 혼합하는 것이 간단하지 않았기 때문입니다. C ++에 최종적으로 추가 된 블록은 이러한 상황에 도움이되었으며 휴대 성을 가능하게 할 것입니다.

부록 편집과 관련하여 C ++ 0x에 대한 예 클로저가 고려되고 있습니다. Raii Scopeed Guards와 함께 사용하여 사용하기 쉬운 솔루션을 제공 할 수 있습니다. Pizer의 웹 로그. 그들은 또한 시도를 흉내내는 데 사용될 수 있습니다. 이 답변 ; 하지만 이것이 정말 좋은 생각입니까? .

비 RAII 유형을 다루어야 할 때에 대한 일종의 스마트 포인터 래퍼 인 내 자신의 솔루션을 추가 할 것이라고 생각했습니다.

다음과 같이 사용 :

Finaliser< IMAPITable, Releaser > contentsTable;
// now contentsTable can be used as if it were of type IMAPITable*,
// but will be automatically released when it goes out of scope.

따라서 Finaliser의 구현은 다음과 같습니다.

/*  Finaliser
    Wrap an object and run some action on it when it runs out of scope.
    (A kind of 'finally.')
    * T: type of wrapped object.
    * R: type of a 'releaser' (class providing static void release( T* object )). */
template< class T, class R >
class Finaliser
{
private:
    T* object_;

public:
    explicit Finaliser( T* object = NULL )
    {
        object_ = object;
    }

    ~Finaliser() throw()
    {
        release();
    }

    Finaliser< T, R >& operator=( T* object )
    {
        if (object_ != object && object_ != NULL)
        {
            release();
        }
        object_ = object;

        return *this;
    }

    T* operator->() const
    {
        return object_;
    }

    T** operator&()
    {
        return &object_;
    }

    operator T*()
    {
        return object_;
    }

private:
    void release() throw()
    {
        R::release< T >( object_ );
    }
};

... 그리고 여기 릴리스가 있습니다 :

/*  Releaser
    Calls Release() on the object (for use with Finaliser). */
class Releaser
{
public:
    template< class T > static void release( T* object )
    {
        if (object != NULL)
        {
            object->Release();
        }
    }
};

무료 ()와 CloseHandle () 용을 포함하여 이와 같은 몇 가지 종류의 릴리스가 있습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top