C++
允许throw
任何类型的对象。从exception
到string
甚至是int
。
但我从未见过throw
除exception
之外的任何其他任何实际应用。
我的问题是,throw
非exception
个对象的应用是什么?
答案 0 :(得分:9)
从实用性的角度来看,几乎没有 1 申请投掷string
s,int
或其他任何非{{1} }}
这不是因为没有迹象表明这样做,而是因为有禁忌症表明你不应该这样做。
有两个主要原因导致您不想抛出任何非std::exception
派生的内容:
std::exception
并且std::string
的构造或副本引发了另一个异常,则会调用string
而你的过程将不复存在。你永远不会有机会terminate
catch
。 std::string
的投掷衍生图使std::exception
以通用方式成为可能。如果你扔了其他东西,那么你需要catch (const std::exception&)
。可以找到关于例外的良好讨论here。
1 几乎没有申请[...]:每条规则都有例外情况,但即使承认这一点,我也从未见过合法< / em>排除投掷catch
的衍生物。
答案 1 :(得分:4)
更多的是黑客而不是语言功能,你可以抛出一个对象,然后捕获它以强制函数“返回”不同于其正常返回类型的东西。
int aFunc()
{
throw foo(); // if you catch that foo, you 've imitated returning foo
return 0; // ok just an int
}
这可能是一个糟糕的设计选择和C ++提供的类型安全的违反,但是你说你有一个在巨大的代码库中大量使用的函数,你想尝试一些改变(这涉及改变返回类型)然后在实际实现更改之前尝试一些东西是肮脏的方式(并且grep整个代码库来做更改)
编辑:
你应该仔细阅读这篇文章。我说“一个糟糕的设计选择”和“C ++提供的类型安全的违反”和“在实际实施变更之前”。如果这还不够警告我不认为那些评论或支持者会是。
另一方面,尝试在6e06行的代码库中更改函数的返回类型666次,以便在将其上载到版本控制系统并打破编译倍数后发现它不是您想要的工作在其他平台上的开发人员的时间比你多。
如果有快捷方式,您不想知道吗?在实施更改并将其实际发布到您的代码库之前,您不会使用它吗?
即使这些问题的答案是“不”,我认为这篇文章是关于探索可能性的,只提一个问题本身并不是“邪恶的”。我个人在Bjarne的演讲http://channel9.msdn.com/Events/GoingNative/GoingNative-2012/Keynote-Bjarne-Stroustrup-Cpp11-Style中听到了这一点,后来他说过不使用这些东西的相同事情。
答案 2 :(得分:1)
你抛出任何你想要的东西,当你抛出它时它总是一个例外。标准库使用从std :: exception继承的类,这是一个设计选择。
如果你觉得抛出一个枚举就足以满足需求,那么为什么要强制你抛出一个对象...
答案 3 :(得分:1)
我不确定是什么原因引发了这个问题,因为在您认为合适的情况下,您可以自由选择“应用程序”。
对象异常的目的是指出发生异常的事实,并且通常用于从thrower到处理程序携带一些特定于异常的信息。如果某个类型在您的应用程序中足以满足此目的,那么您可以将该类型用作“异常”类型。如果需要,您可以抛出int
值,std::string
值和其他任何值。这完全取决于你。
如果您想要从投掷者到处理程序的所有值都是int
值,那么键入int
将作为“例外”类型提供此目的。这就是它的全部内容。
C ++不对您可以抛出的类型强加任何特定要求。因此,实际上没有“异常”类型或“非异常”类型。什么是“异常类型”,什么是“异常类型”由您和您的代码中仅由您决定。你可以抛出任何东西,只要你知道如何抓住它以及如何解释你抓到的东西。
使用类类型表示异常的第一个好处是类类型可以由用户自定义,即您可以根据需要轻松定义任意数量的异常类型。然后,您可以使用许多独立的,非干扰的异常“流”,它们只会抛出并捕获各自类型的异常。
使用类类型表示异常的第二个好处是类类型很容易扩展。即在任何时候,您都可以向异常类型添加额外的“有效负载”信息,并且该有效负载将从抛出异常的位置传送到捕获和处理异常的位置。
如果您对这些好处不感兴趣,可以简单地抛出并捕获int
类型的值来表示您的例外情况。这会奏效。但我几乎可以肯定你会在维护和可扩展性方面迅速遇到这种方法的局限性。
答案 4 :(得分:1)
通常,抛出的任何对象都应该来自
std::exception
。但是也有例外。最多
显而易见:我曾参与过喜欢投掷的项目
int
致电exit()
。当然,这只适用于
main
遵循捕捉int
并返回的惯例
它。 (这样做的好处是所有局部变量都是
如果你打exit()
,他们就不会被破坏。)
在小型一次性测试项目中,我经常会抛出
一个字符串文字(可以用char const*
抓住),哪个
可以立即输出。 (这是不的一个很好的解决方案
任何生产代码,但是当你正在进行实验时
学点东西,似乎可以接受。)
答案 5 :(得分:0)
当@ galop1n回答时,你可以抛出任何你喜欢的东西。但
throw(type())
---&gt;结果catch(type const& e)
catch(std::exception const& e)
捕获所有可记录内容的人的期望。虽然你可能会反驳说他们不应该抓住任何他们不知道它是什么的东西。答案 6 :(得分:0)
我不同意仅应抛出std::exception
的派生词的一般概念。当然,我可以同意,抛出具有复杂数据或行为的对象可能会带来很大的问题,应该格外小心。
但是,这既不表示对抛出类型的继承层次结构没有任何限制,也不表示应用程序采用堆栈展开的方式(或原因)。 throw
操作就是这样:一种干净且定义明确的方法将堆栈展开到定义的点(匹配的catch
),而不必在中间帧中包含显式处理程序。
当然,有一些合法的抛出用例并不表示错误或发生任何exception
-al。以一个简单的语言解释器为例,其中主语言堆栈对应于来宾语言堆栈。为了用来宾语言实现交错并行性,当来宾操作阻塞(或让步)时,堆栈展开正是您需要执行的操作。您想放松到并行性的起点,然后尝试下一个并行分支。这种情况既不是例外,也不是任何类型的错误。
请注意,关键字被称为throw
/ catch
,并且exception
概念并未以任何方式被烘焙到语言中。这是原因之一。