通过引用捕获std::exception?

30

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

catch (exception& e) 中,文章写道:

我们使用引用类型作为异常对象的处理程序(注意类型后面的&符号),因此也可以捕获派生自exception类的类,比如我们的myexception对象。

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


我不理解你最后一段的意思。按引用传递与异常无关,它在C++中是基本的,允许运行时多态性。 - Kerrek SB
2
答案是否定的——你能捕获的对象必须是从你在捕获中提到的异常类型派生出来的。这展示了IS-A关系。如果你只在catch子句中指定子类,那么你不能捕获父类。 - Chris
4个回答

70

使用&与异常一起的原因不是多态性,而是避免切片。如果您不使用&,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!,因为原始异常对象被切片丢失了。如果我们将其更改为&

#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!

3
+1;哇,你的例子和答案看起来非常像我的。你是坐在我后面吗? ;) - Merlyn Morgan-Graham
1
@Merlyn,不是的,我认为这只是展示问题最简单的方式 :) - bdonlan
1
+bdonlan 我不理解 virtual const char *what() const throw() { 这两个函数是什么?what() 和 throw(),你能解释一下这个函数的语法吗?我以前没见过。 - abhimanyuaryan
1
@androidplusios.design 它定义了一个名为what的虚函数,返回const char *,可以在const对象(第二个const)上调用,并且永远不会抛出异常throw()。这是覆盖std::exception上的what()的正确方式。 - bdonlan
挑剔一点:由于std::exception中的what()被定义为虚函数,您可能希望使用const char *what() const throw() override或更好的const char *what() const throw() final - Roi Danton

10
这是否意味着通过使用"&",你也可以捕获父类的异常? 不是的,这并不增加您从哪里捕获异常的范围(例如从包含try/catch代码的类的父类中)。 与按值捕获(没有“&”的catch(std::exception e) - 您仍将捕获任何是std::exception或派生自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

不,& 对异常处理程序的多态性没有任何影响。他们的措辞非常糟糕,似乎表明 & 在某种程度上是有责任的。这不是事实。您是正确的,& 只是传递引用,效率略高一些。

另外,作为一般规则,你真的应该尽量避免cplusplus.com

更新链接:cplusplus.com有什么问题


@sje397 嗯,看起来他们删除了这篇文章,我已经更新了链接。 - Chris Eberle
新链接已失效。 - kingsjester

0

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接