C++抛出异常语法

6

我有一个关于抛出对象语法的一般性问题。考虑以下代码:

#include <stdio.h>

struct bad { };

void func() {
    throw bad;
}

int main(int, char**) {
    try {
        func();
    } catch(bad) {
        printf("Caught\n");
    }

    return 0;
}

这段代码无法编译(g++ 4.4.3),因为“throw”行必须替换为:

throw bad();

为什么会这样呢?如果我要创建一个栈分配的坏对象,我可以像这样构造它:
bad b;
// I can't use 'bad b();' as it is mistaken for a function prototype

我查阅了Stroustrup的书籍(以及这个网站),但是无法找到任何解释似乎对我来说是不一致的。


5
bad b;bad; 并不相同,就像 bad b();bad(); 并不相同。 - Ed S.
3个回答

9
throw bad;

该代码无法运行,因为bad是一种数据类型,一个结构体(struct bad)。你不能抛出一个数据类型,而是需要抛出一个对象,即数据类型的实例。

你需要做的是:

bad obj;
throw obj;

因为这会创建一个bad结构的对象obj,然后抛出该对象。

他也可以像 throw bad(); 这样做,对吧?这样做有什么问题吗? - FailedDev
我明白这一点 - 我只是发现语法与堆栈分配对象的构造方式不一致。我看到其他人似乎持相反的意见,所以我会接受它并继续前进。谢谢。 - Kyle Morgan
1
@FailedDev:一点也没错,规则是“按值抛出,按引用捕获”,只需使用throw bad()即可,它会生成一个临时对象并按值抛出。 - Alok Save
2
@KyleMorgan: 但它根本不矛盾。 bad 是一种类型, bbad 的一个实例。他们是不同的东西。考虑 bad b = bad()。现在更一致了吗? - Ed S.
@Als:不完全是。我更关注的是立即对象调用默认构造函数的语法,我想应该是这个问题。为了区分对象声明和函数原型,省略括号对我来说似乎有点笨拙。因此,在throw语句中应该能够省略括号(根据最初的问题),编译器将能够推断我想要使用默认构造函数抛出一个bad实例(无论如何抛出类型都没有意义)。 - Kyle Morgan
显示剩余2条评论

2
你需要抛出该结构的一个实例。
void func() {
    bad b;
    throw b;
}

0

不同之处在于 throw 的参数是一个对象,而不是一个类型。将变量声明为 bad b 的语法为 [type] [object_name];。类型 != 实例。


不一定非得是一个对象。它可以是一个字面量(例如 throw 1;)。 - Michael Price
@MichaelPrice:throw关键字右侧的内容是一个_expression_表达式。throw 1; 等同于 int t(1); throw t; 被抛出的东西总是一个对象。 - Mooing Duck
@MooingDuck - 你应该看到我在另一个答案中的评论。我承认被抛出的东西总是一个对象(因为声明为“int”的东西是原始类型的对象),但断言“int t(1); throw t;”等同于“throw 1;”取决于优化。在禁用优化的情况下,在clang演示编译器(http://llvm.org/demo/index.cgi)上运行实验后,生成的代码不同。功能上相同,但不同。 - Michael Price
@MichaelPrice:我没有考虑到成为“lvalue”会改变事情。不过,throw int(1);应该是一样的,对吧? - Mooing Duck
@MooingDuck - 看起来 throw int(1);throw 1; 是等价的,至少从clang的输出来看是这样。幸运的是,优化器也使得另一种情况等价了。 - Michael Price

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