RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 813007
Accepted
Stanislav Petrov
Stanislav Petrov
Asked:2020-04-12 12:57:22 +0000 UTC2020-04-12 12:57:22 +0000 UTC 2020-04-12 12:57:22 +0000 UTC

如何捕捉异常

  • 772

为什么这段代码没有捕捉到异常?

#include <iostream>

class A
{
private:

public:
    A()
    {
        std::cout << "A::A()" << std::endl;
    }
    ~A()
    {
        throw 1;
        std::cout << "A::~A(int)" << std::endl;
    }
};

int main()
{
    A* p = nullptr;

    try
    {
        p = new A();
        delete p;
    }
    catch(...)
    {
        std::cout << "catch(...)" << std::endl;
    }

    return 0;
}
c++
  • 2 2 个回答
  • 10 Views

2 个回答

  • Voted
  1. Harry
    2020-04-12T13:04:48Z2020-04-12T13:04:48Z

    一般来说,不建议在析构函数中抛出异常。据我了解(我不会指出标准中的特定位置)——事实上,析构函数被声明为noexcept——这意味着当在它们中生成异常时,terminate.

    在这里,运行此代码:

    #include <iostream>
    #include <stdlib.h>
    
    class A
    {
    private:
    
    public:
        A()
        {
            std::cout << "A::A()" << std::endl;
        }
        ~A()
        {
            throw 1;
            std::cout << "A::~A(int)" << std::endl;
        }
    };
    
    
    
    int main()
    {
    
        std::set_terminate([](){ std::cout << "terminate called\n"; exit(1);});
    
        A* p = nullptr;
    
        try
        {
            p = new A();
            delete p;
        }
        catch(...)
        {
            std::cout << "catch(...)" << std::endl;
        }
    
        return 0;
    }
    

    如您所见,它被调用terminate- 因为在不应该出现的地方抛出异常。

    “我想是的”(c)维尼

    • 7
  2. Best Answer
    Croessmah stands with Russia
    2020-04-12T18:56:32Z2020-04-12T18:56:32Z

    不建议从析构函数中抛出异常,原因有很多。

    • 这可能导致内存泄漏,
    • 无法提供任何安全保证,
    • 在堆栈展开期间可能会引发析构函数的异常,从而根据对象导致不同的后果。

    让我们看看你的代码。

    delete p;
    

    如您所知,首先delete-expression调用析构函数,然后释放内存。如果析构函数抛出异常,那么内存将不会被释放,这将导致泄漏。

    例如,在实现容器时,不可能提供有关异常安全的任何保证。例如:

    vector.push_back();//Вектор был не пуст
    

    假设发生了内存分配。所以旧元素被复制到新的内存区域。如果复制成功,并且在销毁旧对象时抛出了异常,那么我们将得到一部分未销毁的对象和内存泄漏。但是,如果在复制过程中抛出异常,并且向量试图销毁已经构建的对象,并且在销毁它们时会抛出异常,那么我们将得到相同的泄漏,另外一个异常将“飞”得更远。

    如果在堆栈展开期间从自动对象的析构函数中抛出异常,则根据标准,这将导致调用std::terminate

    15.2 构造函数和析构函数

    1. 为在从 try 块到 throw 表达式的路径上构造的自动对象调用析构函数的过程称为“堆栈展开”。[注意:如果在堆栈展开期间调用的析构函数因异常退出,则调用终止 (15.5.1)。所以析构函数通常应该捕获异常,而不是让它们传播出析构函数。——尾注]

    这是来自 C++03 的引用,但行为在后续标准中没有改变。

    从 C++11 开始,所有析构函数默认都有一个异常规范noexcept。如果违反此规范,则调用以下命令std::terminate:

    每当抛出异常并且搜索处理程序 (15.3) 遇到具有不允许异常的异常规范的函数的最外层块时,然后,

    - 如果异常规范是动态异常规范,则调用函数 std::unexpected() (15.5.2),

    - 否则,调用函数 std::terminate() (15.5.1)。

    也就是说,从 C++11 开始,任何离开析构函数std::terminate的异常都会导致程序被调用并崩溃,从而至少提供了统一的行为和提供任何保证的可能性。可以为析构函数指定不同的异常规范:

    ~A() noexcept(false) { /*...*/ }
    

    但同时,如果抛出异常,我们会得到上面指出的所有问题。

    底线:离开析构函数的异常会产生很多问题并且不会提供任何好处,因此一般建议是永远不要让异常离开析构函数。

    • 4

相关问题

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    是否可以在 C++ 中继承类 <---> 结构?

    • 2 个回答
  • Marko Smith

    这种神经网络架构适合文本分类吗?

    • 1 个回答
  • Marko Smith

    为什么分配的工作方式不同?

    • 3 个回答
  • Marko Smith

    控制台中的光标坐标

    • 1 个回答
  • Marko Smith

    如何在 C++ 中删除类的实例?

    • 4 个回答
  • Marko Smith

    点是否属于线段的问题

    • 2 个回答
  • Marko Smith

    json结构错误

    • 1 个回答
  • Marko Smith

    ServiceWorker 中的“获取”事件

    • 1 个回答
  • Marko Smith

    c ++控制台应用程序exe文件[重复]

    • 1 个回答
  • Marko Smith

    按多列从sql表中选择

    • 1 个回答
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Suvitruf - Andrei Apanasik 什么是空? 2020-08-21 01:48:09 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5