0

假设我有这个:

namespace MyNamespace{

class Exception : public std::runtime_error
{
public:
  explicit Exception(const std::string &msg) : std::runtime_error(msg) {}
};

} //namespace MyNamespace

我的程序中有一段代码:

try{
    foo();
}
catch (const MyNamespace::Exception &exc){
    std::cout << exc.what();
}

问题是(我希望你检查我) - 如果我写在 foo 中,我会捕捉到异常:

1)throw MyNamespace::Exception("Hello world!");

在这里我想,是的,我会的,因为我明确指出了异常的类型(并且它是“显式”关键字的必要原因)并且 std::string 没有“显式”关键字,这意味着我可以抛出“Hello world !” 而不是 std::string("Hello world!")

2)throw MyNamespace::Exception(std::string("Hello world!"));

显然,我会的。

3)throw "Hello world!";

在这里,我认为,不,我不会,关键字“显式”存在的原因。

4)throw std::string("Hello world");

没有(同样的原因)

5)如果我没有明确的关键字,我应该从 3-4 个案例中获得期望吗?(我想是的)

更新:6)什么时候会创建临时对象 std::string?在什么时间点?

4

3 回答 3

2

您对 1-4 的答案是正确的,但它们背后的推理有点不对劲。

explicit3)这与关键字无关。之后的表达式的类型throwconst char[12],并且根据规则抛出的异常的类型是const char*

explicit4)同样,与字符串构造函数无关,真的。抛出的类型是std::string并且只有std::string(无论是否引用)类型的处理程序可以捕获它。

5)很明显,不。

6) 抛出异常时。

于 2013-10-22T10:47:29.593 回答
2

throw从 3-5 中的措辞来看,您显然认为 C++ 试图catch将 事实并非如此。该throw语句与任何语句分开考虑catch- 实际上,您可以在编写捕获代码之前编译函数foo及其throw语句,因此它不能选择将 a 转换为std::string捕获代码最终寻找的某种类型......它可能不知道。

抛出的值的类型完全取决于参数的类型throw,因为如果表达式没有出现,则可以在周围的上下文中理解throw。例如:

void foo()
{
     ...
     throw XXX;
}

...抛出与...相同的类型

void foo()
{
     ...
     auto what_will_be_thrown = XXX;
     throw what_will_be_thrown;
}

捕获时不会应用类似const char*的转换,尽管您可以通过公共基类(用于引用或指针)捕获派生类型,当然您可以使用引用等捕获类型。std::stringconst

Re 6) - 无论值的类型是什么,它都是在Exception调用构造函数之前创建的,就像任何其他函数调用时序一样,但在这种情况下,被抛出的对象可能会在与普通函数不同的内存区域中构造调用堆栈,这样它就可以在寻找匹配的 catch 语句时发生的堆栈展开中幸存下来。但是,标准中没有具体说明编译器是如何编排的。

于 2013-10-22T11:09:12.430 回答
1

您对 3 和 4 的理由是错误的,因此,您对 5 的回答也是错误的。原因如下:

当您catch出现异常时,除了转换为基类之外,不会每次都执行转换。所以catch (Foo const&)永远不会捕获任何可转换为的东西Foo,除了 的子类Foo。正是由于这个原因,并且与explicit构造函数无关,您的代码不会捕获抛出的std::stringchar[].

于 2013-10-22T10:48:42.087 回答