这种链接异常的实现如何工作? [英] How does this implementation of chaining exceptions work?

查看:154
本文介绍了这种链接异常的实现如何工作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我之前曾询问过有关如何在C ++中链接异常的问题,并且其中一个答案提供了一个漂亮的解决方案如何做。问题是,我不理解代码,并试图在评论中进行这种讨论是太麻烦了。所以我想,最好是完全开始一个新的问题。

I previously asked a question about how to chaining exceptions in C++, and one of the answers provided a nifty solution to how it can be done. The problem is that I don't understand the code, and trying to have this kind of discussion in the comments is just too much of a bother. So I figured it's better to start a new question entirely.

代码包含在下面,我已经清楚地标记了我没有得到的每个部分。我不明白的描述包括在代码下面。代码由 Potatoswatter 撰写。

The code is included below and I've clearly marked each section which I don't get. A description of what I don't understand is included below the code. The code was written by Potatoswatter.


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();
}

运行代码会产生以下输出:

Running the code gives the following output:

bah
humbug!
meh!






我不明白




What I don't understand


  1. throw; c $ c> -block:我从来没有见过这个。我认为 throw; 有效的唯一地方是在 catch -block中重新抛出所捕获的内容。那么这是做什么的呢?一些调试显然表明抛出的异常是以前抛出的,但是这是一个完全不同的 try -block。事实上,它甚至在 struct 声明之外!

  1. throw; inside try-block: I've never seen this before. The only place I've thought throw; to be valid was inside a catch-block to rethrow what was caught. So what does this do? Some debugging apparently shows that the thrown exception is what was thrown previously, but that was inside a completely different try-block. In fact, it was even outside the struct declaration!

交换字段: b>为什么需要交换例外字段?不只是复制指针就足够了吗?这是为了防止字段指向的结构过早地从堆中删除?

Swap fields: Why do we need to swap the exception fields? Wouldn't just copying of the pointers be enough? Is this to prevent the structures to which the fields point at from being deleted from the heap prematurely?

检查链接 链接的链接: code>不是 NULL (即使删除 NULL 指针没有效果),但为什么需要

Check link and link's link: I can understand checking that link is not NULL (even though deleting a NULL pointer has no effect), but why the need to check the link's link?

抛出异常:为什么需要这个虚拟?它被抛出,但后来下降。为什么我们需要这个作为链的一端?

Throw dummy exception: Why is this dummy needed? It's thrown but then dropped. Why do we need this as an end to the chain?


推荐答案

代码 - 这个potatoswatter的kudos。

Clever code - kudos to potatoswatter on this one. I think that I would have to find some way around the last item though.


  1. throw;

  1. throw; rethrows the active exception. It is only valid if a catch block is on the stack. I can't recall where I came across that tidbit at but it was probably on SO in the context of some other question. The bare throw gives us access to the current exception by catching it in the chained_exception constructor. In other words, prev in the constructor is a reference to the exception that we are currently processing.

你在这里是正确的。

main 中抛出的sentinel异常不应该被删除。这个异常的一个标识属性是链接成员 NULL

The sentinel exception, the one thrown in main, should never be deleted. The one identifying attribute of this exception is that it's link member is NULL.

这是我不喜欢的部分,但不能想到一个简单的方法。只有当 catch 块处于活动状态时,才能调用唯一可见的 chained_exception 构造函数。 IIRC,一个没有活动 catch 块的抛出是一个no-no。因此,解决方法是抛出 main 并将所有代码放在 catch 块中。

This is the part that I don't like but cannot think of an easy way around. The only visible chained_exception constructor can only be called when a catch block is active. IIRC, a bare throw without an active catch block is a no-no. So, the workaround is to throw in main and put all of your code in the catch block.

现在,如果您在多线程代码中尝试此方法,请确保您了解(4)非常好。你必须在你的线程入口点复制这个。

Now, if you try this method in multi-threaded code, make sure that you understand (4) very well. You will have to replicate this in your thread entry point.

这篇关于这种链接异常的实现如何工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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