【问题标题】:catching std::exception by reference?通过引用捕获 std::exception?
【发布时间】:2011-07-20 01:22:33
【问题描述】:

我有一个愚蠢的问题。我读了这篇关于 std::exception http://www.cplusplus.com/doc/tutorial/exceptions/

的文章

catch (exception& e) 上,它说:

我们放置了一个处理程序,它通过引用捕获异常对象(注意类型后面的 & 符号),因此它也捕获从异常派生的类,例如我们的 myex 类 myexception 对象。

这是否意味着通过使用“&”也可以捕获父类的异常?我认为 & 是在 std::exception 中预定义的,因为传递 e (std::exception) 作为引用比传递对象更好。

【问题讨论】:

  • 我不明白你的最后一段。通过引用传递与异常无关,是 C++ 中允许运行时多态性的基础。
  • 答案是否定的——您可以捕获的对象必须源自您正在捕获的异常类型,正如您在帖子中提到的那样。这展示了 IS-A 关系。如果只在 catch 子句中指定子类,则无法捕获父类。

标签: c++


【解决方案1】:

使用带有异常的& 的原因与其说是多态性,不如说是避免slicing。如果您不使用&,C++ 将尝试将抛出的异常复制到新创建的std::exception 中,这可能会在此过程中丢失信息。示例:

#include <stdexcept>
#include <iostream>

class my_exception : public std::exception {
  virtual const char *what() const throw() {
    return "Hello, world!";
  }
};

int main() {
  try {
    throw my_exception();
  } catch (std::exception e) {
    std::cout << e.what() << std::endl;
  }
  return 0;
}

这将打印std::exception(在我的情况下为St9exception)而不是Hello, world! 的默认消息,因为原始异常对象已被切片丢失。如果我们将其更改为&amp;

#include <stdexcept>
#include <iostream>

class my_exception : public std::exception {
  virtual const char *what() const throw() {
    return "Hello, world!";
  }
};

int main() {
  try {
    throw my_exception();
  } catch (std::exception &e) {
    std::cout << e.what() << std::endl;
  }
  return 0;
}

现在我们确实看到了Hello, world!

【讨论】:

  • +1;哇,你的例子和答案看起来非常像我的。你坐在我后面吗? ;)
  • @Merlyn,不,我认为这只是证明问题的最简单方法:)
  • +bdonlan 我不明白virtual const char *what() const throw() { 两个函数? what() & throw() 你能解释一下这个函数的语法吗?我以前没见过。
  • @androidplusios.design 它定义了一个名为 what 的虚函数,返回 const char *,可以在 const 对象(第二个 const)上调用,并且从不抛出异常 throw() .这是在std::exception 上覆盖what() 的正确方法
  • 吹毛求疵:由于what()std::exception 中被定义为虚拟,您可能希望使用const char *what() const throw() override 或更好的const char *what() const throw() final
【解决方案2】:

这是否意味着使用“&”也可以捕获父类的异常?

不,这不会增加捕获异常的范围(例如,从包含 try/catch 代码的类的父类)。

与按值捕获(catch(std::exception e) 没有 &amp; 相比,它也不会增加可以捕获的异常类型 - 您仍然会捕获每个异常是 std::exception 或派生自它)。

它增加的是捕获异常时实际获得的数据量。

如果从std::exception 派生的异常被抛出,并且您通过值捕获它,那么您将抛出该异常类中的任何额外行为。由于Slicing,它在异常类上破坏了polymorphism

一个例子:

class MyException : public std::exception
{
public:
    virtual const char* what() const
    {
        return "hello, from my exception!";
    }
};

// ...

try
{
    throw MyException();
}
catch(std::exception& e)
{
    // This will print "hello, from my exception!"
    std::cout << e.what() << "\n";
}

// ...

try
{
    throw MyException();
}
catch(std::exception e)
{
    // This will print "Unknown exception"
    std::cout << e.what() << "\n";
}

【讨论】:

    【解决方案3】:

    不,&amp; 绝对与异常处理程序的多态性无关。他们的措辞很差,这似乎表明&amp; 有某种责任。不是这种情况。你是对的,&amp; 只是通过引用传递,效率更高。

    一般情况下,you should really try to avoid cplusplus.com

    更新链接: What's wrong with cplusplus.com

    【讨论】:

    • @sje397 嗯,他们好像删除了这篇文章,我已经更新了链接。
    【解决方案4】:

    这里使用异常引用可以减少创建的临时对象,同时也可以保持多态性。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-04-16
      • 1970-01-01
      • 1970-01-01
      • 2021-04-07
      • 2016-02-08
      • 2019-08-28
      • 1970-01-01
      相关资源
      最近更新 更多