Joh*_*ell 59 c++ error-handling exception-handling
注意:我不是在扮演魔鬼的拥护者或类似的东西 - 我只是真的好奇,因为我自己不在这个营地.
标准库中的大多数类型都具有可以抛出异常的变异函数(例如,如果内存分配失败)或者可以抛出异常的非变异函数(例如,超出边界的索引访问器).除此之外,许多自由函数可以抛出异常(例如operator new
和dynamic_cast<T&>
).
你如何在"我们不使用例外"的背景下实际处理这个问题?
你是否试图永远不会调用可以投掷的功能?(我无法看到它的规模如何,所以如果是这种情况,我很想知道你是如何实现这一目标的)
你没事吧和标准库中投掷,你把"我们不使用异常"为"我们从来不扔的异常我们的代码,我们从来没有赶上从异常等的代码"?
您是否通过编译器开关完全禁用异常处理?如果是这样,标准库的异常抛出部分如何工作?
编辑您的构造函数,它们是否会失败,或者按照惯例使用具有专用init函数的两步构造,该函数可以在失败时返回错误代码(构造函数不能),或者您是否执行其他操作?
编辑在问题开始后1周进行了一些小的澄清......下面的评论和问题中的大部分内容都集中在为什么方面的例外与"别的东西".我的兴趣是不是在这,但是当你选择做"别的东西",如何你处理标准库部件是不抛出异常?
Kev*_*inZ 42
我会为自己和世界的角落回答.我写了c ++ 14(一旦编译器有更好的支持将是17)延迟关键的财务应用程序,处理庞大的金钱,不能下降.规则集是:
内存被合并并预先分配,因此初始化后没有malloc调用.数据结构要么是不朽的,要么是可以复制的,因此几乎不存在析构函数(有一些例外,例如范围保护).基本上,我们正在做C +类型安全+模板+ lambda.当然,通过编译器开关禁用异常.对于STL,它的好部分(即:algorithm,numeric,type_traits,iterator,atomic,...)都是可用的.抛出异常的部分很好地与运行时内存分配部分和半OO部分重合,因此我们可以一次性去掉所有的内容:流,除了std :: array,std :: string之外的容器.
为什么这样?
Zou*_*uch 20
在我们的例子中,我们通过编译器禁用异常(例如,-fno-exceptions
对于gcc).
在gcc的情况下,它们使用_GLIBCXX_THROW_OR_ABORT
被定义为的宏
#ifndef _GLIBCXX_THROW_OR_ABORT
# if __cpp_exceptions
# define _GLIBCXX_THROW_OR_ABORT(_EXC) (throw (_EXC))
# else
# define _GLIBCXX_THROW_OR_ABORT(_EXC) (__builtin_abort())
# endif
#endif
Run Code Online (Sandbox Code Playgroud)
(你可以libstdc++-v3/include/bits/c++config
在最新的gcc版本中找到它).
然后,你必须处理抛出异常中止的事实.您仍然可以捕获信号并打印堆栈(SO上有一个很好的答案可以解释这一点),但您最好避免发生这种情况(至少在发布中).
如果你想要一些例子,而不是像
try {
Foo foo = mymap.at("foo");
// ...
} catch (std::exception& e) {}
Run Code Online (Sandbox Code Playgroud)
你可以做
auto it = mymap.find("foo");
if (it != mymap.end()) {
Foo foo = it->second;
// ...
}
Run Code Online (Sandbox Code Playgroud)
abl*_*abl 18
我也想指出,该询问不使用异常时,有关于标准库的一个更普遍的问题:你是否使用标准库,当你在"我们不使用异常"阵营的一个是?
标准图书馆很重.在一些"我们不使用例外"阵营中,例如许多GameDev公司,使用更适合STL的替代品 - 主要基于EASTL或TTL.这些库无论如何都不使用异常,因为第八代控制台没有很好地处理它们(甚至根本没有).对于尖端的AAA生产代码,无论如何异常都太重了,所以在这种情况下这是一个双赢的场景.
换句话说,对于许多程序员来说,关闭异常是完全没有使用STL的.
Nia*_*all 10
注意我使用例外...但我不得不这样做.
你是否试图永远不会调用可以投掷的功能?(我无法看到它的规模如何,所以如果是这种情况,我很想知道你是如何实现这一目标的)
这可能是不可行的,至少是大规模的.许多函数可以抛出,避免它们完全削弱您的代码库.
您对标准库抛出是否正常,并且您将"我们不使用异常"视为"我们从不从代码中抛出异常而我们从不捕获其他代码的异常"?
你几乎必须要好......如果库代码要抛出异常并且你的代码不会处理它,则终止是默认行为.
您是否通过编译器开关完全禁用异常处理?如果是这样,标准库的异常抛出部分如何工作?
这是可能的(在某些项目类型的某些时候很流行); 编译器可以/可能支持这一点,但是您需要查阅他们的文档以了解结果将会是什么和可能是什么(以及在这些条件下支持哪些语言功能).
通常,当抛出异常时,程序将需要中止或以其他方式退出.一些编码标准仍然需要这一点,我想到了JSF编码标准(IIRC).
那些"不使用例外"的人的一般策略
大多数函数都有一组前提条件,可以在调用之前检查它们.检查那些.如果不满足,则不要拨打电话; 回到该代码中的错误处理.对于那些你无法检查的功能,以确保满足前提条件......不多,该程序可能会中止.
您可以考虑避免引发异常的库 - 您在标准库的上下文中询问了这一点,因此这不太合适,但它仍然是一个选项.
其他可能的策略; 我知道这听起来很陈旧,但选择一种不使用它们的语言.C可以做得很好......
...问题的关键(你与标准库的交互,如果有的话),我很想听听你的构造函数.它们是否会失败,或者按照惯例使用具有专用init函数的两步构造,该函数可以在失败时返回错误代码(构造函数不能)?或者你的战略是什么?
如果使用构造函数,通常有两种方法用于指示失败;
enum
指示失败以及失败是什么.在对象的构造和采取适当的操作之后可以对此进行询问.init()
方法来完成(或完成)构造.如果存在某些故障,则成员方法可以返回错误.该init()
技术的使用通常是有利的,因为它可以链接并且比内部"错误"代码更好地扩展.
同样,这些技术来自不存在异常的环境(例如C).使用诸如C++之类的语言没有例外限制了它的可用性和标准库的广度的有用性.
我没有试图完全回答你提出的问题,我只是将google作为代码库的一个例子,它不使用异常作为处理错误的机制.
在Google C++代码库中,每个可能失败的函数都会返回一个status
对象,该对象具有ok
指定被调用者结果的方法.
如果开发人员忽略了返回status
对象,他们已经配置了GCC以使编译失败.
另外,从它们提供的小开源代码(例如LevelDB库)来看,它们似乎并没有那么多地使用STL,因此异常处理变得罕见.正如泰特斯温特斯在CPPCon的讲座中所说,他们"尊重标准,但不要崇拜它".