C++ 在哪里可以找到有关C++/STL方法异常保证?

C++ 在哪里可以找到有关C++/STL方法异常保证?,c++,exception-handling,C++,Exception Handling,前几天我在编写带有异常处理的代码,我有一些关于异常、它们的保证和可丢弃性的问题 基本上,假设你有: class X { string m_str; X() : m_str("foo")//what if this throws? { ifstream b("a.in")//what if this throws? } 在浏览了所有我能找到的文章之后,我仍然不知道什么是处理这个问题的干净方法 假设我有如下代码: { ... X myInstanceOfClassX;

前几天我在编写带有异常处理的代码,我有一些关于异常、它们的保证和可丢弃性的问题

基本上,假设你有:

class X {
string m_str;
X() : m_str("foo")//what if this throws?
{
    ifstream b("a.in")//what if this throws?
}
在浏览了所有我能找到的文章之后,我仍然不知道什么是处理这个问题的干净方法

假设我有如下代码:

{
    ...
    X myInstanceOfClassX;
    ...
}
我应该将代码包装在
catch(exception&)
中吗?如果我这样做,
string
ifstream
是否保证了一个强有力的保证,即没有资源泄漏,没有任何东西被打开了一半

另外,如果我的类抛出从exception派生的
myexception
catch(exception&)
似乎让它通过了。这就剩下了
捕获(…)
哪个IIRC捕获访问冲突?。?还有别的办法吗

然后在某个地方有一条信息,对象构造函数的子构造函数中抛出的任何异常都不应该被捕获,并且构造函数应该在任何成员对象抛出时抛出

如果上面的代码不是从构造函数调用的,而是从常规函数
void foo()
调用的,我应该捕获哪些异常呢?outofmemory\u某物,filenotfound\u某物?哪里可以找到STL对象可以抛出的定义?它们是特定于实现的吗

我可以在哪里澄清我对这个话题的所有疑问和疑问

到目前为止,处理异常似乎就像在一大堆gooo中跳舞。错误代码似乎更简单、更安全……

至于是否引发(更重要的是,引发哪些)异常,则主要由实现来决定。我看不出有什么必要尝试抓住这些——我的意思是,如果失败了,你会怎么做?是否有任何合理的方法可以从抛出的异常中恢复


请记住,例如,如果无法打开文件,则不会引发异常-这只会导致流被设置为失败状态。

如果其中任何一个引发异常

class X {
string m_str;
X() : m_str("foo")//what if this throws?
{
    ifstream b("a.in")//what if this throws?
}
那么您正在创建的对象将不存在。
如果在对象的构造函数中抛出异常,则所有完全创建的成员都将被析构函数(使用其析构函数),对象的内存将返回给系统。因此,在抛出点未完全构造的任何构件都不会被销毁(因为它们尚未创建)

  • 如果m_str()抛出初始值设定项列表,则该对象将永远不存在
  • 如果ifstream抛出到身体中,那么m_str将被销毁,对象将永远不存在
我应该将代码包装在catch(exception&)中吗?如果我这样做了,字符串和ifstream是否能保证一个强有力的保证,即没有资源泄漏,没有任何东西被半开

即使捕捉到异常(在对象外部),也没有对象可处理,因为它从未存在过(对象仅在构造函数完成后才开始其生命周期)

在上述情况下,您可以保证没有泄漏或开放资源

另外,如果我的类抛出myexception,它是从exception派生的,那么catch(exception&)似乎会让它通过。这就给我留下了一个捕获(…)哪个IIRC捕获了访问违规?。?还有别的办法吗

如果您的异常是从std::exception派生的,那么
catch(std::exception&)
将起作用。如果它不起作用,那么你就做错了(但是我们需要更多的细节(比如抛出的代码和捕获的代码,英语描述是不够的))

然后在某个地方有一条信息,对象构造函数的子构造函数中抛出的任何异常都不应该被捕获,并且构造函数应该在任何成员对象抛出时抛出

也许是最好的选择,一般来说,这是个不错的建议

如果上面的代码不是从构造函数调用的,而是从常规函数void foo()调用的,我应该捕获哪些异常呢?outofmemory\u某物,filenotfound\u某物?哪里可以找到STL对象可以抛出的定义?它们是特定于实现的吗

只有在可以采取措施的情况下,才应该捕获异常。通常情况下,这没什么,唐;t捕获它们让应用程序正常退出(通过异常解除堆栈)

我可以在哪里澄清我对这个话题的所有疑问和疑问

你的问题太多了,很难回答。
我可以推荐

到目前为止,处理异常似乎就像在一大堆gooo中跳舞。错误代码看起来更简单更安全

你错了。例外情况要容易得多。你似乎想得太多了,弄糊涂了。这并不是说错误代码没有它们的位置

如果出现问题
,而您无法在本地修复它
,则抛出异常。本标准中的所有类都是在考虑异常的情况下设计的,它们的行为都是正确的。那就只剩下你的课了

经验法则:(适用于您的对象)
  • 确保您的类在析构函数中自行清理
  • 如果对象包含资源,请确保“遵守3的规则”
  • 每个对象的资源不得超过一个。
    注意:您可以有多个对象,如std::string或std::ifstream,因为它们是控制资源的对象(它们各自控制一个资源,因此您的类不控制资源)。资源(在此上下文中)是您必须手动创建/销毁的资源

这是,其余的自动神奇地工作。

< p>关于标准库如何工作的唯一权威参考,包括允许在哪些条件下抛出哪些异常类型,是C++语言标准。多年前,它以电子形式提供,价格合理,但不幸的是
my_class a; // If this throws, everything past this line is not accessible.
            // Therefore, you cannot use a.
my_class* b;

try
{
    b = new my_class; // If this throws, ...
}
catch (...)
{
    // b has undefined state here (but no memory is leaked)
}
template <typename T>
struct my_vector
{
    // This is why it is not advisable to roll your own vector.
    my_vector(size_t n, const T& x)
    {
        begin = static_cast<T*>(custom_allocator(n * sizeof(T)));
        end = begin + n;

        size_t k = 0;
        try
        {
            // This can throw...
            for (; k != n; k++) new(begin + k) T(x); 
        }
        catch (...)
        {
            // ... so destroy everything and bail out
            while (--k) (begin + k)->~T();
            custom_deallocator(begin);
            throw;
        }
    }

private:
    T* begin;
    T* end;
};