2011-08-22 18 views
13

Co to jest dobry sposób w C++, aby wykryć w destruktorze, że jest uruchamiany podczas rozwijania stosu z powodu wyrzucanego wyjątku, w przeciwieństwie do normalnego wyjścia z zakresu wyzwalającego destruktor? Chciałbym wiedzieć, żebym mógł utworzyć klasę, która ma jakiś kod czyszczenia, który jest zawsze uruchamiany przy normalnym wyjściu, ale pomijany, gdy wystąpi wyjątek.Wykrywanie, kiedy destruktor działa z powodu odrzucenia wyjątku?

+0

Interesujące pytanie! Kusi mnie, aby powiedzieć, że nie da się tego zrobić, ponieważ obiekty tak naprawdę nie wiedzą o tym, że wyjątek jest aktywny, po prostu wychodzą poza zakres, ponieważ wyjątek rozwija stos, tak jak gdyby wypadł z jakiegokolwiek innego zakres. Jeśli potrzebujesz czegoś konkretnego "hacka" dla platformy ... –

+1

Ciekawe, dlaczego chcesz uniknąć czyszczenia podczas rozwijania stosu? –

+0

@Eric Z: Pomyślałem, że użyję tego do automatycznego rejestrowania 'stack'. Coś w stylu 'Log xxx (" funcA - ", arg1, arg2, arg3);', ale oprzyrządowanie funkcji jest nużące. –

Odpowiedz

16

std::uncaught_exception() (zdefiniowane w <exception>) powie Ci w destructor gdyby był nazywany ze względu na wyjątek:

class A 
{ 
public: 
    ~A() 
    { 
     if (std::uncaught_exception()) { 
      // Called because of an exception 
     } else { 
      // No exception 
     } 
    } 
}; 
+0

Miło, nigdy nie wiedziałem, że to istnieje! :-) –

+0

Nie tak miło, jak mogłoby się wydawać - zobacz połączony artykuł na moim poście. – Simon

0

Oto jeden sposób mogę myśleć, ale wydaje się niezgrabny:

{ 
    myCleanupClass unwindAction; 
    try { 
    // do some work which may throw exception. 
    } catch (...) { 
    unwindAction.disableDestructorWork(); 
    throw; 
    } 
} 
1

Nie rób tego, chyba że masz dobry powód. Rozwijanie stosów jest taką funkcją językową, że wszystkie automatyczne obiekty w bloku try zostaną wymuszone, aby zwolnić zasoby, tak aby zasoby wewnątrz nich mogły zostać uwolnione.

Chcesz pominąć czyszczenie w dtor podczas rozwijania stosu, które omija pierwotną intencję. I będziesz narażony na ryzyko przeciekania zasobów.

Przykład

class CDBConnection 
{ 
    public: 
    CDBConnection() 
    { 
     m_db.open(); 
    } 
    ~CDBConnection() 
    { 
     if (!std::uncaught_exception()) 
     m_db.close(); 

     // if this is called during a stack unwinding, 
     // your DB connection will not be closed for sure. 
     // That's a resource leakage. 
    } 
    //.. 
    private: 
    DB m_db; 
}; 

void main() 
{ 
    //.. 
    try 
    { 
    // code that may throw 
    CDBConnection db; 
    //..   
    } 
    catch(const CDBException& exp) 
    { 
    // properly handle the exception 
    } 
} 
4

Prawdopodobnie this artykuł pomoże. Artykuł pokaże Ci problemy ze std :: uncaught_exception() i zawiera porady dotyczące radzenia sobie z wyjątkami w destruktorach.

Powiązane problemy