如何构建< stdexcept>或< system_error>异常不投掷? [英] How to construct a <stdexcept> or <system_error> exception without throwing?

查看:192
本文介绍了如何构建< stdexcept>或< system_error>异常不投掷?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

< stdexcept> (例如 std :: logic_error std :: runtime_error 及其子类,例如 std :: system_error )具有期望字符串参数的构造函数,例如:

Exceptions defined in <stdexcept> (e.g. std::logic_error, std::runtime_error and their subclasses such as std::system_error) have constructors expecting string arguments, e.g.:

domain_error(const string& what_arg);
domain_error(const char* what_arg);

with postconditions

with postconditions

strcmp(what(), what_arg.c_str()) == 0
strcmp(what(), what_arg) == 0

。没有要求传递给构造函数的这些参数在这些异常的生命周期内保持有效,因此确保后置条件成立的唯一方法是复制并存储这些动态字符串。这需要记忆,所以我假设他们的构造本身可以抛出 std :: bad_alloc 或类似的东西,这通常是最意想不到的。这导致问题,因为我在野外看到的每个代码示例都鼓励人们编写代码如

respectively. There is no requirement that these arguments passed to the constructors remain valid during the lifetime of these exceptions, so the only way to ensure that the postconditions hold, is to duplicate and store these dynamic strings. This requires memory, so I assume that their construction itself may throw std::bad_alloc or similar, which is usually most unexpected. This causes problems, because every code example I've seen in the wild encourages people to write code like

if (haveError)
    throw std::runtime_error("BOO!"); // May throw std::bad_alloc instead?!

而在某些其他位置预先构建异常似乎更安全,例如: / p>

whereas it would seem to be much safer to construct the exception beforehand in some other place, e.g:

struct A {
    // During allocation of A one would often expect std::bad_alloc anyway:
    A() : m_someException("BOO!") {}
    void f() {
        /* Do stuff */
        if (haveError)
            throw m_someException;
            /* Note that according to §18.8.1.2 all standard library
               classes deriving from `std::exception` must have publicly
               accessible copy constructors and copy assignment operators
               that do not exit with an exception. In implementations such
               exception instances most likely share the common string
               with all their copies. */
    }
    std::runtime_error const m_someException;
};

这使我非常谨慎的图书馆抛出任何这样的异常,例如甚至从C ++ 11中的< regex> 中的regex_error

This makes me very cautious of libraries which throw any such exceptions, e.g even regex_error from <regex> in C++11!!!

strong>为什么这些异常没有no-throw / noexcept构造函数? C ++核心指导原则是否有此发言?

Why don't these exceptions have no-throw/noexcept constructors? Does the C++ core guidelines have a say on this?

PS:个人我在这个异常祖先链中,将会离开 what()一个纯抽象方法。

PS: Personally I would have left what() a pure abstract method at this point in the exception ancestry chain.

推荐答案

if (haveError)
    throw std::runtime_error("BOO!"); // May throw std::bad_alloc instead?!

应该已经照顾所有的清理,所以在大多数情况下,有一个 std :: bad_alloc 抛出而不是一个 std :: runtime_error 真的不会有太大的区别。

by the time you reach this throw you should have already taken care of all clean up so in most cases, having a std::bad_alloc thrown instead of a std::runtime_error won't make much of a difference really.

唯一的例外情况是,当使用异常来控制程序的流程时,我可以做的事情 - 我经常使用如下代码: / p>

The only exceptional case, I can thing of is when exceptions are used to control the flow of a program - I tend to do this very often with code such as:

try { 
  auto face = detectFace(); // may throw a custom no_face_exception or a many_faces_exception
  // do work with face
} 
catch (no_face_exception& e) {
  std::cout << "no face detected\n";
}
catch (many_faces_exception& e) {
  std::cout << "too many faces detected\n";
}

在这种特殊情况下,无法分配内存将导致 detectFace 可以引发 std :: bad_alloc 而不会造成灾难性的崩溃。抛出之前首先分配异常,根据您的建议,根本不会改变任何东西 - 程序仍然会崩溃,因为$ code> std :: bad_alloc ,因为分配仍然会失败。解决这个问题的唯一方法是简单地捕捉 std :: bad_alloc

In this particular case failure to allocate memory would cause detectFace to throw a std::bad_alloc instead which would cause a disastrous crash. First allocating the exceptions before throwing, as you suggested, would not change anything at all - the program would still crash with a std::bad_alloc since the allocation would still fail. The only way around this problem would be to simply catch the std::bad_alloc:

catch (std::bad_alloc& e) {
  std::cout << "bad alloc reported\n";
}

这篇关于如何构建&lt; stdexcept&gt;或&lt; system_error&gt;异常不投掷?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆