如何捕获派生(多态)异常对象并将其重新抛出到第二级? 在我的情况下,派生对象仅保留到“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)
答案 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