不抛出但依赖于库的类

时间:2014-04-20 18:53:58

标签: c++ stl

我编写了一些不抛出异常但却使用STL的类,而STL可以抛出异常。例如,在我的类中有一些函数使用std :: vector,std :: list,std :: string。复制字符串或创建向量时,STL可能会抛出,对吧?所以我无法将我的课程描述为免费的,对吗?

在这样的情况下,你们做了什么?你在try / catch中包装每个函数吗?你怎么形容你的课程?感谢

5 个答案:

答案 0 :(得分:4)

正确,如果从特定成员函数(包括构造函数,编译器为您提供的隐式调用等)调用的任何内容都可以抛出异常,那么成员函数可以抛出异常。所以它不是免费的例外。

关于如何处理它:它实际上取决于你的代码应该做什么,以及"如果它抛出异常"你能做什么?你可能想要把它捕获到某个地方,但是由于你可能已经完成了一些愚蠢和/或内存不足的情况,你很可能无法对这种情况做很多事情。 (当然,如果你使用例如std::vector::at()超出范围的值,那么它会抛出一个例外 - 那就是做一些愚蠢的事情 - 同样是我和我#39;已完成几次,const char* p = 0; .... std:string str(p); - 它当然可能会崩溃而不是抛出异常,但我的编译器似乎从此抛出了bad_something异常)。任何这些东西,如果它们不是有意的话,可能是#34;你的代码的死亡无论如何"。如果你使用std::vector::at()指数不好而且你打算使用#34;那么你可能会重新考虑你的设计 - 例外情况是昂贵的"与if (vec.size() > index) ... else ...

相比

我不确定是否存在&#34的特定术语;我的类不会抛出异常,但使用的标准库可以执行"。

答案 1 :(得分:1)

幸运的是,由于分配问题导致STL类抛出的可能性非常小:更有可能的是,你的进程被OOM杀手击落而不是分配失败。所以我倾向于忽略这些异常,只是让它们崩溃程序。我非常激动不使用异常,所以我写的代码中没有try{}catch(){}

当我不是一个项目的时候,我也不会尝试包装每个函数调用,我只是将我的函数声明为throw()。这样做的结果是,我调用的任何其他函数中出现的任何意外异常都会安全地使程序崩溃,而不是传播到可能捕获它的其他函数。这样我可以确定在没有人注意的情况下,我的代码中没有重要的部分被跳过。

答案 2 :(得分:1)

参考GotW#82(http://gotw.ca/gotw/082.htm)添加异常规范总是不好的做法:

  

异常规范可能导致令人惊讶的性能命中   例如,如果编译器关闭函数的内联   例外规范。运行时意外()错误并不总是如此   你想要发生什么样的异常错误   规格意味着抓住。你通常不会写有用的   因为你的功能模板的异常规范   通常不能告诉他们操作的类型可能会抛出。

答案 3 :(得分:1)

你的设计有缺陷。

  

我编写了一些不抛出异常但却使用STL的类,而STL可以抛出异常。

您需要回答这个问题 - 如果您的程序由于STL故障而失败,您会怎么做?您唯一的选择是抛出异常或返回值。 (或者当场崩溃应用程序。)当然,您有一个选择是返回您编写的自定义类SuccessOrFailure。成功时,它将包含实际的返回数据,如果失败,它将包含一些描述出错的信息。换句话说,您可以将已经抛出的异常堵塞到返回值中,并强制客户端代码检查错误的返回值,并执行如果抛出异常将会执行的操作,仅编写C样式返回在发明异常之前, C编程的一部分的值代码。但如果这是你的设计决定,那就是你必须要做的。

或者你可以尝试返回一些意味着“失败”的值,例如,对于一个整数,返回0或-1。当然,这个解决方案只有在您的实际功能明确只返回正数时才有效,如果您使用固定数字,它将不会显示有关错误的任何信息。

我的观点是,你需要弄清楚如何处理失败,无论你是否抛出异常。“不使用异常”不回答问题,它只是忽略了工作。

有效理由不使用我见过的例外

  • 您正在维护旧的面向返回值的代码,在这种情况下,您需要做好将异常转换为不同返回代码的敷衍工作
  • 您可以处理所有错误(例如mixin或日志库),在这种情况下,您应该包装在try / catch中并处理所有错误

答案 4 :(得分:1)

在现代C ++中,您可以使用noexcept

struct Foo {
  void bar() noexcept(true) {
    some_function_that_throws();
  }
};

void safe_function() {
  // safe as nothing here can ever throw
  Foo* foo = new(std::nothrow) Foo();
  if (foo)
    foo->bar();
  delete foo;
}

这里需要注意的是,如果抛出异常并且没有在带有noexcept的方法中捕获,则进程将退出。有些人认为这可能是好事;它类似于使用断言。该行为最终类似于不担心异常,因为未捕获的异常通常会终止该过程。主要的区别在于,在适当的时候使用noexcept函数可以生成更快更精简的代码(即使在所谓的“零开销异常”ABI中)。

在某些行业中,只需使用-fno-exceptions或等效编译即可。 STL实现通常支持此模式。有些提供了一些略微非标准的行为,以便在需要这种检查的情况下检查或处理故障。请记住,大多数STL异常源于内存不足情况下的某种程度,即使有异常,也很少能恢复。简单地崩溃与其他任何事情都没有太大的不同。有一些应用程序处理这些情况很重要,但是压倒性的可能性是你没有在其中一个上工作(如果你是,C ++可能不是最好的语言选择)。