链接异常的实现是如何工作的?

2024-05-14

我之前问过一个question https://stackoverflow.com/questions/3543725/should-exceptions-be-chained-in-c关于如何在 C++ 中链接异常,其中一个答案为如何完成它提供了一个很好的解决方案。问题是我看不懂代码,试图在评论中进行这种讨论实在是太麻烦了。所以我认为最好完全开始一个新问题。

代码包含在下面,我已经清楚地标记了我不明白的每个部分。代码下面包含了我不明白的内容的描述。代码是由土豆拍 https://stackoverflow.com/users/153285/potatoswatter.


Code


struct exception_data { // abstract base class; may contain anything
    virtual ~exception_data() {}
};

struct chained_exception : std::exception {
    chained_exception( std::string const &s;, exception_data *d = NULL )
        : data(d), descr(s) {
        try {
            link = new chained_exception;

            // ----------------------------------------------------------------
            //   How does this work (section 1)?
            throw;
            // ----------------------------------------------------------------

        } catch ( chained_exception &prev; ) {
            // ----------------------------------------------------------------
            //   How does this work (section 2)?
            swap( *link, prev );
            // ----------------------------------------------------------------
        } // catch std::bad_alloc somehow...
    }

    friend void swap( chained_exception &lhs;, chained_exception &rhs; ) {
        std::swap( lhs.link, rhs.link );
        std::swap( lhs.data, rhs.data );
        swap( lhs.descr, rhs.descr );
    }

    virtual char const *what() const throw() { return descr.c_str(); }

    virtual ~chained_exception() throw() {
        // --------------------------------------------------------------------
        //   How does this work (section 3)?
        if ( link && link->link ) delete link; // do not delete terminator
        // --------------------------------------------------------------------
        delete data;
    }

    chained_exception *link; // always on heap
    exception_data *data; // always on heap
    std::string descr; // keeps data on heap

private:
    chained_exception() : link(), data() {}
    friend int main();
};

void f() {
    try {
        throw chained_exception( "humbug!" );
    } catch ( std::exception & ) {
        try {
            throw chained_exception( "bah" );
        } catch ( chained_exception &e; ) {
            chained_exception *ep = &e;
            for ( chained_exception *ep = &e; ep->link; ep = ep->link ) {
                // Print ep->what() to std::cerr
            }
        }
    }

    try {
        throw chained_exception( "meh!" );
    } catch ( chained_exception &e; ) {
        for ( chained_exception *ep = &e; ep->link; ep = ep->link ) {
            // Print ep->what() to std::cerr
        }
    }
}

int main() try {
    // ------------------------------------------------------------------------
    //   How does this work (section 4)?
    throw chained_exception(); // create dummy end-of-chain
    // ------------------------------------------------------------------------
} catch( chained_exception & ) {
    // body of main goes here
    f();
}

运行代码给出以下输出:

bah
humbug!
meh!

我不明白什么

  1. throw; inside try-block:我以前从未见过这个。我唯一想到的地方throw;有效的是在一个catch-阻止重新抛出捕获的东西。那么这有什么作用呢?一些调试显然表明抛出的异常是之前抛出的异常,但那是在完全不同的内部try-堵塞。事实上,甚至在外面struct宣言!

  2. 交换字段:为什么我们需要swap异常字段?仅仅复制指针还不够吗?这是为了防止字段指向的结构被过早地从堆中删除吗?

  3. Check link and link's link:我可以理解检查link is not NULL(即使删除NULL指针没有作用),但是为什么需要检查link's link?

  4. 抛出虚拟异常:为什么需要这个假人?它被抛出,但随后掉落。为什么我们需要这个作为链条的末端?


聪明的代码——对potatoswatter 的这一代码表示敬意。我认为我必须找到解决最后一项的方法。

  1. throw;重新抛出活动异常。它仅在以下情况下有效:catch块在堆栈上。我不记得我是在哪里看到这个花絮的,但它可能是在其他一些问题的背景下出现的。裸露的抛出让我们可以通过在chained_exception构造函数。换句话说,prev构造函数中是对我们当前正在处理的异常的引用。

  2. 你在这里是正确的。这可以防止重复删除。

  3. 哨兵异常,抛出的异常main,永远不应该被删除。此异常的一个识别属性是link成员是NULL.

  4. 这是我不喜欢的部分,但想不出一个简单的方法。唯一可见的chained_exception构造函数只能在以下情况下被调用catch块处于活动状态。 IIRC,没有主动的裸投catch阻止是一个禁忌。所以,解决方法是投入main并将所有代码放入catch block.

现在,如果您在多线程代码中尝试此方法,请确保您很好地理解 (4)。您必须在线程入口点中复制此内容。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

链接异常的实现是如何工作的? 的相关文章

  • 更快的算法来计算有多少数字可以被范围内的特定整数整除

    int a b c d 0 cin gt gt a gt gt b gt gt c for int i a i lt b i if i c 0 d cout lt
  • SetWindowsHookEx 函数返回 NULL

    我正在研究 DLL 注入 但收到错误如下 挂接进程失败 87 参数不正确 目标进程和dll都是64位的 注入代码为 BOOL HookInjection TCHAR target TCHAR dll name https msdn micr
  • C修改printf()输出到文件

    有没有办法修改printf为了将字符串输出到文件而不是控制台 我尝试在互联网上查找一些内容 发现了类似的电话dup dup2 and fflush这可能与此有关 EDIT 也许我不清楚 问题是这是C考试问题 问题如下 解释一个通常将字符串输
  • 切换图片框可见性 C#

    为什么图片框控件的可见性属性在这里不起作用 我最初将它们设置为 false 以便在屏幕加载时它们不可见 但后来我想切换这个 我已完成以下操作 但似乎不起作用 这是一个 Windows 窗体应用程序 private void Action w
  • 使用不带参数的 Split() 时,默认分隔符是什么?

    所以我看了看String Split 今天 C 中的方法 我意识到你也可以向它传递零参数 这是我从未考虑过的 使用时默认的分隔符是什么Split 没有任何参数 如果没有值 则为空白 来源自here https msdn microsoft
  • 如何将字节块读入结构体

    我有一个需要处理的资源文件 它包含一组文件 首先 资源文件列出了其中包含的所有文件 以及一些其他数据 例如在此结构中 struct FileEntry byte Value1 char Filename 12 byte Value2 byt
  • 将成员函数作为参数传递/c++

    我想用 C 实现一个类b可以通过封装该迭代器类型的成员集进行某种迭代 喜欢 b object for each x do function f so 函数 f会得到每个人的x成员并做任何事情 比方说 void function f x me
  • 导出到 CSV 时 Gridview 出现空行

    这个问题是由进一步讨论引发的这个问题 https stackoverflow com questions 6674555 export gridview data into csv file 6674589 noredirect 1 com
  • Microsoft.Graph - 如何从具有不同用户名的共享邮箱发送?

    我目前正在将使用 SMTP 的服务代码移植到 Office 365 通过 SMTP 我可以使用 发件人 字段在来自共享收件箱的邮件上设置不同的用户名 同时保留共享电子邮箱地址 这似乎无法通过 Office 365 运行 其工艺流程为 客户填
  • 使用scanf()时如何区分整数和字符

    我只是使用该功能scanf 代码如下 scanf d a printf d a 当我输入1时 它会像我想要的那样打印1 但即使我输入 1a 它也会像以前一样打印 1 当用户输入非整数时 例如 2 3 12ab 1 a 我想向用户显示 输入整
  • c# 如何生成锦标赛括号 HTML 表

    所以我已经被这个问题困扰了三个星期 但我一生都无法弄清楚 我想做的是使用表格获得这种输出 演示 http www esl world net masters season6 hanover sc2 playoffs rankings htt
  • 数据损坏 C++ 和 Python 之间的管道

    我正在编写一些代码 从 Python 获取二进制数据 将其通过管道传输到 C 对数据进行一些处理 在本例中计算互信息度量 然后将结果通过管道传输回 Python 在测试时 我发现如果我发送的数据是一组尺寸小于 1500 X 1500 的 2
  • 为什么WCF中不允许方法重载?

    假设这是一个ServiceContract ServiceContract public interface MyService OperationContract int Sum int x int y OperationContract
  • 如何不在类中实现接口的功能?

    面试时面试官问了我以下问题 但我不知道这个问题的答案是什么 请帮忙 如果我不想 我必须做什么 在我的类中实现一个函数 在接口中声明为 由我班实施 Edited 我正在使用 NET 和 C 如果有人可以提供 C 示例代码示例 那就太好了 Th
  • `cosf`、`sinf` 等不在 `std` 中 [重复]

    这个问题在这里已经有答案了 根据这里的讨论 我有报告了一个错误 https bugs launchpad net ubuntu source gcc 8 bug 1831385给 Ubuntu 开发者 编译以下示例 C 程序时 includ
  • 当在 Repository/UnitOrWork 之上使用 Service 类时,我应该在哪里放置逻辑不适合 Repository 的常用数据访问代码?

    In my 先前的问题 https stackoverflow com questions 24906548 using the generic repository unit of work pattern in large projec
  • 无法通过 LINQ to Entities 使用某些功能?

    我正在尝试使用 LINQ 查询在项目上实现搜索功能 由于数据有时包含带有重音符号和其他符号的字符 因此我创建了一种方法来删除这些字符以进行搜索 这是我的代码 var addresses from a in db Addresses join
  • 为什么 C# 接口名称前面加上“I”

    这种命名约定背后的基本原理是什么 我没有看到任何好处 额外的前缀只会污染 API 我的想法与康拉德一致response https stackoverflow com a 222502 9898与此相关的question https sta
  • 使用剪贴板 SetText 换行

    如何使用 SetText 方法添加换行符 I tried Clipboard SetText eee n xxxx 但当我将剪贴板数据粘贴到记事本中时 它没有给我预期的结果 预期结果 eee xxxx 我怎样才能做到这一点 Windows
  • 如何确定给定方法可以抛出哪些异常?

    我的问题和这个真的一样 找出 C 中方法可能抛出的异常 https stackoverflow com questions 264747 finding out what exceptions a method might throw in

随机推荐