문제

쓰고 라이브러리를 휴대용입니다.따라서,그것은에 의존하지 않 glibc 또는 Microsoft 확장 프로그램 또는 다른 것이지에 표준입니다.나는 좋은 계층 구조의 클래스에서 파생되는 std::예외 사용하는 오류를 처리에서 논리 및 입력이 있습니다.는 특정 형식의 예외가 발생했에 특정 파일을 줄 수은 유용하지만,는 방법을 알고 실행 가지고 있는 것으로 훨씬 더 가치가있다,그래서 내가 찾고있는 방법의 습득한다.

내가 알고 있는 데이터를 이용할 수 있을 때는 건물에 대하여 glibc 기능을 사용하여 execinfo.h(참조하십시오 질문 76822 다)및을 통해 StackWalk 인터페이스에서 Microsoft C++구현하십시오( 질문 126450어),하지만 나는 아주 많이 하는 것을 피하십시오지 않은 휴대용입니다.

나는 생각을 구현하는 이 기능을에서 자신이 형태:

class myException : public std::exception
{
public:
  ...
  void AddCall( std::string s )
  { m_vCallStack.push_back( s ); }
  std::string ToStr() const
  {
    std::string l_sRet = "";
    ...
    l_sRet += "Call stack:\n";
    for( int i = 0; i < m_vCallStack.size(); i++ )
      l_sRet += "  " + m_vCallStack[i] + "\n";
    ...
    return l_sRet;
  }
private:
  ...
  std::vector< std::string > m_vCallStack;
};

ret_type some_function( param_1, param_2, param_3 )
{
  try
  {
    ...
  }
  catch( myException e )
  {
    e.AddCall( "some_function( " + param_1 + ", " + param_2 + ", " + param_3 + " )" );
    throw e;
  }
}

int main( int argc, char * argv[] )
{
  try
  {
    ...
  }
  catch ( myException e )
  {
    std::cerr << "Caught exception: \n" << e.ToStr();
    return 1;
  }
  return 0;
}

는 이 끔찍한 아이디어?그것은 많은 것을 의미 할 것입니다 작업을 추가하려고/catch 블록 모든 기능,그러나 내가 살 수 있습니다.그것은 작동하지 않을 경우 예외의 원인이 메모리 손상이나 메모리 부족하지만,그 시점에서 당신은 꽤 많은 조 anyway.를 제공할 수 있습니다 잘못된 정보면 어떤 기능을 쌓지 않는 예외를 포착,추가 자신이 목록,그리고를 다시 발생시키지만,나는 적어도 보증을 제공하는 모든 나의 라이브러리 함수가 이렇게.과는 달리는"진짜"스택 추적이지 않겠습을 얻을 줄 수에서 함수를 호출하지만 적어도 나는 것은 뭔가 다른 것이 있어야 합니다.

나의 주요 관심사는 가능성이 감속을 일으키는 원인이 될 것이 없을 때에도 예외는 실제로 발생합니다.이러한 모든 것을 할 시도/catch 블록을 추가로 필요한 설정하고 눈물로 각 함수 호출,또는 어떻게든 처리에서 컴파일까?또는 있는 기타 문제가 있으로 간주되지 않?

도움이 되었습니까?

해결책

나는 이것이 정말로 나쁜 생각이라고 생각합니다.

이식성은 매우 합당한 목표이지만, 방해, 성능-스핑 및 열등한 구현의 솔루션을 초래할 때는 아닙니다.

내가 작업 한 모든 플랫폼 (Windows/Linux/PS2/iPhone 등)은 예외가 발생할 때 스택을 걸을 수있는 방법을 제공하고 주소를 기능 이름과 일치시킵니다. 예, 이들 중 어느 것도 휴대용이 없지만보고 프레임 워크는 가능할 수 있으며 일반적으로 플랫폼 별 버전의 스택 워킹 코드를 작성하는 데 하루나 이틀 이내에 걸립니다.

크로스 플랫폼 솔루션을 작성/유지 관리하는 것 보다이 시간이 적을뿐만 아니라 결과는 훨씬 나았습니다.

  • 함수를 수정할 필요가 없습니다
  • 트랩은 표준 또는 타사 라이브러리에서 충돌합니다
  • 모든 기능에서 시도/캐치가 필요하지 않습니다 (느리고 메모리 집약적)

다른 팁

Nested Diagnostic Context 다.여기에 작은 힌트:

class NDC {
public:
    static NDC* getContextForCurrentThread();
    int addEntry(char const* file, unsigned lineNo);
    void removeEntry(int key);
    void dump(std::ostream& os);
    void clear();
};

class Scope {
public:
    Scope(char const *file, unsigned lineNo) {
       NDC *ctx = NDC::getContextForCurrentThread();
       myKey = ctx->addEntry(file,lineNo);
    }
    ~Scope() {
       if (!std::uncaught_exception()) {
           NDC *ctx = NDC::getContextForCurrentThread();
           ctx->removeEntry(myKey);
       }
    }
private:
    int myKey;
};
#define DECLARE_NDC() Scope s__(__FILE__,__LINE__)

void f() {
    DECLARE_NDC(); // always declare the scope
    // only use try/catch when you want to handle an exception
    // and dump the stack
    try {
       // do stuff in here
    } catch (...) {
       NDC* ctx = NDC::getContextForCurrentThread();
       ctx->dump(std::cerr);
       ctx->clear();
    }
}

오버헤드에서의 구현 NDC.내가 연주했으로 느리게 평가 버전뿐만 아니라 다른 하나는 유지의 고정된 항목을 뿐입니다.키 포인트 사용하는 경우 생성자 및 소멸자 처리할 스택을 그렇게 당신이 필요로 하지 않는 그 모든 불쾌한 try/catch 블록고 명시적 조작이다.

유일한 플랫폼을 보시려 두통입니다 getContextForCurrentThread() 방법입니다.당신이 사용할 수 있는 플랫폼을 특정한 구현에 스레드를 사용하여 로컬 저장소 작업을 처리하기 위해서 대부분의 경우 모든 경우.

당신은 더 높은 성능을 지향하고 라이브 세계에서의 로그 파일,다음 범위를 변경 개최하는 포인터 파일 이름과 줄번호와를 생략 NDC 것 전부:

class Scope {
public:
    Scope(char const* f, unsigned l): fileName(f), lineNo(l) {}
    ~Scope() {
        if (std::uncaught_exception()) {
            log_error("%s(%u): stack unwind due to exception\n",
                      fileName, lineNo);
        }
    }
private:
    char const* fileName;
    unsigned lineNo;
};

이렇게 하면 좋은 스택 추적에서의 로그 파일의 경우 예외가 발생합니다.에 대한 필요가 없습니다 실제 스택을 걷는,단지 작은 로그 메시지 예외가 발생되는;)

결국 "플랫폼 독립"방법이 있다고 생각하지 않습니다. 결국, 스택 워크 나 특별한 GCC 스택 추적 기능이 필요하지 않을 것입니다.

약간 지저분한 일이지만,이 구현 방법은 스택 추적에 액세스하기위한 일관된 인터페이스를 제공하는 클래스를 만드는 것입니다. 그런 다음 적절한 플랫폼 별 방법을 사용하여 실제로 배치하는 구현에 #ifdef가 있습니다. 추적을 함께 쌓으십시오.

이렇게하면 클래스 사용이 플랫폼 독립적이며 다른 플랫폼을 타겟팅하려면 해당 클래스를 수정해야합니다.

디버거에서 :

예외가 발생하는 위치의 스택 추적을 얻으려면 std :: 예외 생성자의 브레이크 포인트를 stcik합니다.

따라서 예외가 생성되면 디버거가 중지되고 해당 시점에서 스택 추적을 볼 수 있습니다. 완벽하지는 않지만 대부분의 시간이 작동합니다.

스택 관리는 매우 빠르게 복잡 해지는 간단한 것 중 하나입니다. 전문 라이브러리를 위해 남겨 두는 것이 좋습니다. Libunwind를 사용해 보셨습니까? 훌륭하게 작동하고 Afaik은 휴대용이지만 Windows에서는 시도한 적이 없습니다.

이것은 느리지 만 작동하는 것처럼 보입니다.

빠르고 휴대용 스택 추적을 만드는 데있어 문제를 이해 한 바에 따르면 스택 구현은 OS와 CPU가 모두 포함되므로 암시 적으로 플랫폼 특정 문제라는 것입니다. 대안은 MS/GLIBC 함수를 사용하고 #ifdef 및 적절한 전처리 기준 (예 : _WIN32)을 사용하여 다른 빌드에서 플랫폼 특정 솔루션을 구현하는 것입니다.

스택 사용은 플랫폼과 구현에 따라 다르기 때문에 완전히 휴대용을 직접 수행 할 수있는 방법이 없습니다. 그러나 플랫폼 및 컴파일러 별 구현에 대한 휴대용 인터페이스를 구축하여 가능한 한 많은 문제를 현지화 할 수 있습니다. IMHO, 이것이 최선의 접근법이 될 것입니다.

트레이서 구현은 사용 가능한 플랫폼 특정 도우미 라이브러리에 연결됩니다. 그런 다음 예외가 발생한 경우에만 작동하며 캐치 블록에서 호출 한 경우에만 작동합니다. 최소 API는 단순히 전체 트레이스를 포함하는 문자열을 반환합니다.

코더가 콜 체인에서 캐치 및 재투자 처리를 주입하도록 요구하는 것은 일부 플랫폼에서 상당한 런타임 비용이 있으며 향후 유지 보수 비용이 크게 부과됩니다.

즉, 캐치/던지기 메커니즘을 사용하기로 선택한 경우 C ++조차도 여전히 C 프리 프로세서를 사용할 수 있고 매크로가 있다는 것을 잊지 마십시오. __FILE__ 그리고 __LINE__ 정의됩니다. 추적 정보에 소스 파일 이름과 줄 번호를 포함시키는 데 사용할 수 있습니다.

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