【问题标题】:How to throw an exception by its run-time type?如何通过其运行时类型抛出异常?
【发布时间】:2011-03-24 14:42:33
【问题描述】:

我想调用一个可能引发异常的函数。如果它确实引发了异常,我想捕获它并将异常对象传递给处理函数。处理函数的默认实现只是抛出异常。以下是用于说明问题的精简代码:

struct base_exception : exception {
  char const* what() const throw() { return "base_exception"; }
};

struct derived_exception : base_exception {
  char const* what() const throw() { return "derived_exception"; }
};

void exception_handler( base_exception const &e ) {
  throw e; // always throws a base_exception object even if e is a derived_exception
}

int main() {
  try {
    throw derived_exception();
  }
  catch ( base_exception const &e ) {
    try {
      cout << e.what() << endl; // prints "derived_exception" as expected
      exception_handler( e );
    }
    catch ( base_exception const &e ) {
      cout << e.what() << endl; // prints "base_exception" due to object slicing
    }
  }
}

但是,exception_handler() 中的throw e 会抛出异常的静态类型的副本,即base_exception。我怎样才能让exception_handler() 抛出具有derived_exception 正确运行时类型的实际 异常?或者我怎样才能重新设计东西以获得我想要的东西?

【问题讨论】:

  • throw e;更改为throw;
  • 顺便说一句:有什么方法可以防止异常切片(例如,通过编译时错误)?程序员很容易输入“e”并得到错误的行为。
  • @Paul J. Lucas:您可以尝试使异常不可复制
  • @Erik:C++ 标准要求所有异常对象都具有可访问的复制构造函数:“当抛出的对象是类对象,并且用于初始化临时副本的复制构造函数不可访问时,程序格式错误(即使临时对象可以被消除)。”
  • @Paul J. Lucas:那就不知道了——也许是 throw new foo 和 catch 指针。我认为一个人应该得到一个新的 Q。

标签: c++ exception-handling


【解决方案1】:

您可以将throw_me 虚函数放在基异常类中,并让每个派生类覆盖它。派生类可以抛出正确的最派生类型,而无需切片。尽管函数在每个类中具有相同的定义,但它们并不相同——*this 的类型在每种情况下都不同。

struct base_exception : exception
{
  char const* what() const throw() { return "base_exception"; }
  virtual void throw_me() const { throw *this; }
};

struct derived_exception : base_exception
{
  char const* what() const throw() { return "derived_exception"; }
  virtual void throw_me() const { throw *this; }
};

void exception_handler( base_exception const &e ) {
  e.throw_me();
} 

【讨论】:

  • @PaulJ.Lucas,哇——我不认为一个老问题的新答案会引起任何关注。谢谢!
【解决方案2】:

您可以使用throw; 重新抛出捕获的异常。您也可以使用模板。

template&lt;typename T&gt; void rethrow(const T&amp; t) { throw t; }

【讨论】:

  • 模板在这种情况下没有用 - 他正在捕捉base_exception const &amp;
【解决方案3】:

Throw by value, catch by reference。它会为您省去很多麻烦。

【讨论】:

    【解决方案4】:

    您要查找的内容称为“传播”异常。为此,您必须在 catch 块内使用不带参数的 throw 关键字。它不会复制异常,并且该异常将被下一个catch 块在其途中捕获,或者如果它没有再次被捕获,则将使您的程序中止。

    【讨论】:

    • 您没有仔细阅读问题。代码必须调用 exception_handler() 函数。由于它没有捕获异常,它不能简单地说“抛出”。
    猜你喜欢
    • 2010-11-02
    • 2012-08-21
    • 2011-10-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多