如何捕获派生(多态)异常对象并将其重新抛出到第二级?

时间:2014-04-29 09:17:53

标签: c++ exception exception-handling try-catch

如何捕获派生(多态)异常对象并将其重新抛出到第二级? 在我的情况下,派生对象仅保留到“1级”。

我理解c ++编译器完成的'返回值优化'。 在我看来,在下面的代码中,'e'的引用应该不再在'Level 2'有效,但是编译器正在做一些隐式创建本地基类的Exception对象,并且我正在丢失从'Level 0'抛出的原始ExtException。 / p>

我的问题是 我如何将'ExtException'对象保留到'Level 2'?

#include <string>
#include <iostream>

using std::endl;

typedef std::string pstring;


class Exception
{
    public:
        Exception ( ) {
            my_id = ++static_count;
            std:: cout << "+Exception obj created.  ID: " << my_id << "  (Total: " << static_count << ")" << endl;
        }

        Exception ( const Exception &e ) {
            my_id = ++static_count;
            std:: cout << "+Exception obj created.  ID: " << my_id << "  (Total: " << static_count << ")" << endl;
        }

        virtual ~Exception() {
            --static_count;
            std:: cout << "-Exception obj deleted.  ID: " << my_id << "  (Total: " << static_count << ")" << endl;
        }

    private:
        static int static_count;
        int        my_id;
};
int Exception:: static_count = 0;



class ExtException : public Exception {
    public:
        ExtException () : Exception()
        { 
            std:: cout << "++ExtException obj created" << endl;
        }

        ExtException ( const ExtException &e ) : Exception()
        { 
            std:: cout << "++ExtException obj created" << endl;
        }

        ~ExtException () {
            std:: cout << "--ExtException obj deleted" << endl;
        }
};





void foo2 () {
    throw ExtException();   // Level 0 throw
}


void foo1 () 
{
    try {
        foo2 ();
    } catch ( Exception &e ) {
        // In my normal understanding of c++ 'e' should no longer be valid here 
        // as it was created on a stack which is no longer exists (i.e Level 0 is scoped out).
        //
        // _BUT_  (actually it is valid. and it is valid because of RVO compiler "Return value optimization"

        std:: cout << "\n--- foo1 catch" << endl;
        throw e;  // Level 1 throw
    }
}


void foo () 
{
    try {
        foo1 ();
    } catch ( Exception &e ) {
        // !!! CAUTION !!!
        // In my opinion 'e' must not be valid here as the original "ExtException" must be destroyed till 
        // this point (which is actually destroyed check output trace).
        // It is destroyed because RVO works for one level only...
        //
        // wait a minute... here the compiler has not left 'e' for FMR hit, instead it has created a new temporary object of 'Exception' class and
        //  'e' is referring to that.
        //
        // Here comes my real question!!!  'e' is no longer referring to an actual  ExtException object but the temporary one, 
        // how could I modify this code to access ExtException object created at 'Level 0'?

        std:: cout << "\n--- foo catch" << endl;
        throw e;  // Level 2 throw
    }
}


int main (void) {

    try {
        foo  ();
    } catch (...) { }
    return 1;
}

以下是上述代码的结果:

+Exception obj created.  ID: 1  (Total: 1)
++ExtException obj created

--- foo1 catch
+Exception obj created.  ID: 2  (Total: 2)
--ExtException obj deleted
-Exception obj deleted.  ID: 1  (Total: 1)

--- foo catch
+Exception obj created.  ID: 2  (Total: 2)
-Exception obj deleted.  ID: 2  (Total: 1)
-Exception obj deleted.  ID: 2  (Total: 0)

2 个答案:

答案 0 :(得分:4)

首选&#34; throw&#34;在&#34;扔e&#34;对于多态异常。

参考:

http://ptgmedia.pearsoncmg.com/images/0321113586/items/sutter_item73.pdf

答案 1 :(得分:3)

  

[C++11: 15.1/3]: throw-expression 初始化一个临时对象,称为异常对象,其类型通过删除任何顶级cv-来确定来自throw操作数的静态类型的限定符,并将类型从“T的数组”或“返回的函数T”调整为“指向T的指针”或“指向函数返回T的指针”。 临时值是一个左值,用于初始化匹配处理程序中指定的变量(15.3)。如果异常对象的类型是不完整类型或指向不完整类型的指针(可能是cv-qualified),则程序格式不正确。除了这些限制和15.3中提到的类型匹配限制外, throw的操作数被完全视为调用中的函数参数(5.2.2)或返回的操作数言。

简而言之,你正在切片,尽管异常处理程序已经接受了引用。

重新投掷应该通过单独编写throw来完成。这正是它的目的:

  

[C++11: 15.1/8]:没有操作数的 throw-expression 重新抛出当前处理的异常(15.3)。 使用现有临时值重新激活该异常;没有创建新的临时异常对象。 [..]

所以:

throw e;  // no
throw;    // yes