Mic*_*hne 10 c++ exception object-slicing
我刚刚在代码中修复了一个非常微妙的错误,这是由异常切片造成的,我现在想确保我完全理解发生了什么.
这是我们的基本异常类,派生类和相关函数:
class Exception
{
public:
  // construction
  Exception(int code, const char* format="", ...);
  virtual ~Exception(void);
  <snip - get/set routines and print function>
protected:
private:
  int mCode;                // thrower sets this
  char mMessage[Exception::MessageLen]; // thrower says this FIXME: use String
};
class Derived : public Exception {
public:
  Derived (const char* throwerSays) : Exception(1, throwerSays) {};
};
void innercall {
  <do stuff>
  throw Derived("Bad things happened!");
}
void outercall {
  try {
    innercall();
  }
  catch(Exception& e)
  {
    printf("Exception seen here! %s %d\n", __FILE__, __LINE__);
    throw e;
  }
}
该bug当然是外部调用最终抛出异常,而不是Derived.我的错误是由于调用堆栈中的高位尝试捕获Derived失败而导致的.
现在,我只想确保理解 - 我相信在'throw e'行,使用默认的复制构造函数创建一个新的Exception对象.这是真的发生了什么?
如果是这样,我是否可以锁定将被抛出的对象的复制构造函数?我真的更喜欢这种情况不会再次发生,我们的代码没有理由复制Exception对象(我知道).
请不要评论我们有自己的异常层次结构这一事实.这是一个我正在努力纠正的旧设计(我正在取得良好的进展.我已经摆脱了本土的字符串类,以及许多本土容器.)
更新:要明确的是,在我提出问题之前,我已经修复了错误(通过将'throw e'更改为'throw').我只是想确认发生了什么.
Mar*_*som 21
抛出一个对象时,实际上是在抛出一个对象的副本,而不是原始对象的副本.想一想 - 原始对象在堆栈中,但堆栈正在展开并失效.
我相信这是标准的一部分,但我没有副本可供参考.
catch块中抛出的异常类型是catch的基本类型,而不是抛出的对象的类型.绕过这个问题的方法是,throw;而不是throw e;将抛出原始捕获的异常.
jal*_*alf 10
一个快速的谷歌建议是的,你要扔复制构造函数是必需的,必须是公开的.(这是有道理的,因为你正在初始化一个副本e并抛出它.)
无论如何,只需使用throw而不指定异常对象,重新抛出在中捕获的内容catch.不应该解决问题吗?
  catch(Exception& e)
  {
    printf("Exception seen here! %s %d\n", __FILE__, __LINE__);
    throw;
  }
是.
throw e;
抛出静态类型的异常,e无论e实际是什么.在这种情况下,Derived异常将复制到Exception使用复制构造函数.
在这种情况下你可以
throw;
Derived正确地获取异常气泡.
如果你对其他一些情况下的多态投掷很感兴趣,请参阅总是如此有用的C++ FAQ Lite.