2010-03-19 2 views
7

Есть некоторые статьи заключительных «никогда не сгенерирует исключение из деструктора», и «станд :: uncaught_exception() не является полезным», например:права использования станда :: uncaught_exception в деструкторе

Но, похоже, я не понимаю. Поэтому я написал небольшой пример тестирования (см. Ниже).

Поскольку все в порядке с примером тестирования, я был бы очень признателен за некоторые комментарии относительно того, что может быть неправильным с ним?

Результаты тестирования:

./main

 
    Foo::~Foo(): caught exception - but have pending exception - ignoring 
    int main(int, char**): caught exception: from int Foo::bar(int) 

./main 1

 
    Foo::~Foo(): caught exception - but *no* exception is pending - rethrowing 
    int main(int, char**): caught exception: from Foo::~Foo() 

Пример:

// file main.cpp 
// build with e.g. "make main" 
// tested successfully on Ubuntu-Karmic with g++ v4.4.1 
#include <iostream> 

class Foo { 
    public: 

    int bar(int i) { 
    if (0 == i) 
     throw(std::string("from ") + __PRETTY_FUNCTION__); 
    else 
     return i+1; 
    } 

    ~Foo() { 
    bool exc_pending=std::uncaught_exception(); 
    try { 
     bar(0); 
    } catch (const std::string &e) { 
     // ensure that no new exception has been created in the meantime 
     if (std::uncaught_exception()) exc_pending = true; 

     if (exc_pending) { 
     std::cerr << __PRETTY_FUNCTION__ 
        << ": caught exception - but have pending exception - ignoring" 
        << std::endl; 
     } else { 
     std::cerr << __PRETTY_FUNCTION__ 
        << ": caught exception - but *no* exception is pending - rethrowing" 
        << std::endl; 
     throw(std::string("from ") + __PRETTY_FUNCTION__); 
     } 
    } 
    } 

}; 

int main(int argc, char** argv) { 
    try { 
    Foo f; 
    // will throw an exception in Foo::bar() if no arguments given. Otherwise 
    // an exception from Foo::~Foo() is thrown. 
    f.bar(argc-1); 
    } catch (const std::string &e) { 
    std::cerr << __PRETTY_FUNCTION__ << ": caught exception: " << e << std::endl; 
    } 
    return 0; 
} 

ДОБАВЛЕНО : Другими словами: несмотря на предупреждения в некоторых статьях, он работает так, как ожидалось - так что может быть с ним не так?

+2

Что вы хотите сказать? Кажется, вы наблюдаете за ожидаемым поведением механизма, который вы не должны использовать. Рассматриваете ли вы его использование за пределами тестового/экспериментального контекста и почему? – Potatoswatter

+0

@Potatoswatter: вопрос в том, что: 'несмотря на предупреждения в некоторых статьях, он работает так, как ожидалось, - так что может быть не так?' – 2010-03-19 05:40:28

+0

Яркий нарс, но это не цитирует сказанное, и невозможно понять, чего ожидать, подходящим или безопасным в вашем контексте без дополнительной информации. Безопасный маршрут, как скажет вам Герб Саттер и многие другие, заключается не в том, чтобы выбраться из деструктора в первую очередь. – Potatoswatter

ответ

5

В коде отсутствует ничего технически неправильно. Это абсолютно безопасно в том, что вы никогда не будете случайно прекращены, потому что вы выбросили исключение, когда это было небезопасно. Проблема в том, что он также не пригодится, поскольку иногда он также не будет генерировать исключение, если это безопасно. Документация вашего деструктора в основном должна сказать: «это может или не может вызвать исключение».

Если это время от времени не будет исключение, вы, возможно, никогда не исключите исключение. Таким образом, вы, по крайней мере, последовательны.

6

Herb Sutter ссылается на другую проблему. Он говорит о:

try 
{ 
} 
catch (...) 
{ 
    try 
    { 
     // here, std::uncaught_exception() will return true 
     // but it is still safe to throw an exception because 
     // we have opened a new try block 
    } 
    catch (...) 
    { 
    } 
} 

Таким образом, проблема в том, что если std::uncaught_exception() возвращает истину, вы не знаете точно, можно ли безопасно бросить исключение или нет. В итоге вам нужно избегать бросать исключение, когда std::uncaught_exception() возвращает true только для того, чтобы быть в безопасности.

+0

@Samuel: '... ссылаясь на другой isssue ...' Это то, что я тоже думал. И - поскольку я не генерирую исключение, когда uncaught_exception() возвращает true - считаете ли вы, что мой подход является безопасным? – 2010-03-19 05:43:49

+0

Это на самом деле не так. Ваше исключение поймано в этот момент. Вы должны поместить try/catch в деструктор, который вызывается во время разворачивания стека (из-за активного исключения). В этой ситуации исключение * * активно разворачивает стек, но вы правы тогда внутри блока try/catch, где вы можете * исключить исключение. – dascandy

Смежные вопросы