2013-02-18 23 views
11

Jest to swego rodzaju kontynuacją na Why can't Alexandrescu use std::uncaught_exception() to implement SCOPE_FAIL in ScopeGuard11?Czy istnieje jakaś sztuczka do wykrywania, czy obiekt jest tworzony podczas wykonywania innego destruktora?

chciałbym wykryć, czy ktoś jest tworzenie MyClass w destruktora innej klasy (lub z aktywnym destructor gdzieś na stos wywołań).

class MyClass 
{ 
public: 
    MyClass(){ 
     assert(???what to put here????); 
    } 
} 

void f(){ 
    MyClass m; //whether this asserts should be context dependant 
} 

class OtherClass{ 
    ~OtherClass(){ 
     MyClass m; //this should assert 
     f();  //this should too; 
    } 
} 

int main() 
{ 
    MyClass m; //this should not assert 
    f();   //this should also not assert 
} 

Jedna próba może być:

assert(!std::uncaught_exception()); 

ale to będzie działać tylko wtedy, gdy destruktor jest wywoływany z powodu wyjątku, jeśli nie jest ona wywoływana, ponieważ obiekt wyszedł z zakresu.

+7

Jeśli nie zaprojektujesz tych destruktorów w sposób jawny, aby sygnalizować ich wykonanie, wątpię, aby było to możliwe. Zasadniczo nie możesz określić, skąd twoja funkcja została wywołana. –

+0

Jak przenośne ma być rozwiązanie? – Flexo

+0

Możesz specjalizować swoje rozwiązanie do konkretnej wersji kompilatora i zbadać stos w konstruktorze 'MyClass', aby znaleźć destruktor' OtherClass'. Osobiście uważam, że jest to zbyt dużo pracy dla tego, czym jest ... i będzie źródłem błędów. – Synxis

Odpowiedz

1

nie można tego wykryć i nie chcesz tego robić. to nie jest sprawa twojej klasy. jeśli ktoś zadzwoni do ciebie z noexcept destructor, będzie wychwytywał wyjątki

0

Nie można wykryć, w jaki sposób wywoływana jest funkcja, chyba że wywołujesz tę informację.

Ponadto, jak pamiętam, Visual C++ nigdy nie zaimplementował std::uncaught_exception, więc byłoby to niezgłoszone (dla przenośnego kodu) nawet tam, gdzie wiadomo było, że żaden destruktor nie wywołał żadnego bloku try.

Jednak nie jest łatwo wykryć, czy zakres został wyłączony z powodu wyjątku, czy nie.

Po prostu umieść ten zakres w bloku try -block; po to jest to.

Na przykład

class Transaction 
{ 
private: 
    bool failed_; 
    Transaction(Transaction const&); // deleted 
    Transaction& operator=(Transaction const&); // deleted 

public: 
    void fail() { failed_ = true; } 

    void commit() { ... } 

    // More functionality, then 

    ~Transaction() 
    { 
     if(failed_) { rollback(); } 
    } 

    Transaction(): failed_(false) {} 
}; 

void foo() 
{ 
    Transaction transaction; 

    try 
    { 
     // blah blah 
    } 
    catch(...) 
    { 
     transaction.fail(); 
     throw; 
    } 
} 

Zastrzeżenie: Nie używałem tego wzoru, więc nie może potwierdzić, jak to jest praktyczne.