• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            旅途

            如果想飛得高,就該把地平線忘掉

            VC++中的異常與標(biāo)準(zhǔn)C++異常的差別和聯(lián)系(轉(zhuǎn)載自Microsoft Systems Journal 1999)

            I can use two approaches for throwing an exception. The first approach is

            														 CMyException myException;     throw myException;  
            												
            and the second is:
            														 CMyException* pMyException = new CMyException();        throw pMyException;  
            												
            As far as I can figure out, the disadvantage of the first method is that the object is first constructed on the stack and then copied again to be passed from throw. The thing that I don't understand about the second approach is, who is responsible for freeing the CMyException object? MFC always uses the second approach, but none of the sample code that shows catching MFC exceptions has code to free the exception object. So, who's freeing it?

            A Good question. The answer may surprise you. But first, let me give you the quick lowdown on exceptions, borrowed from Scott Meyers' excellent book, More Effective C++ (Addison-Wesley, 1995), Item #13. There are three ways you can throw/catch exceptions: by pointer, by value, or by reference.
            If you throw/catch by pointer, you must allocate the exception object to throw, then delete it when you catch. This approach involves no extra copying, but there's a problem. If the exception was thrown using

            														 static CMyException me(...); throw &me;
            												
            your program will [insert bad turn of events here] if the code that catches the exception tries to delete it. It may be fairly unusual to throw a static exception object, but it can be useful sometimes. The point is, there's no way the code that catches the exception can know whether the object was allocated from the heap or static memory, so there's no way for it to be absolutely sure whether to delete it. And it goes without saying that you can't throw a stack object using this method:
            														 CMyException me(...);  throw &me;  
            												
            Everyone knows that a stack object no longer exists when control leaves the function containing it.
            The second approach for throwing and catching exceptions is to throw/catch by value.
            														 // throw code CMyException me; throw me;    // catch code  catch (CException e) {     // handle it }  
            												
            This avoids the allocation/destruction problem since the object is passed on the stack as a value, but at the cost of copying the object twice—once when the exception is thrown, and again when the exception is caught. You can avoid the first copy by writing
            														 throw CMyException(...);  
            												
            which creates the CMyException directly on the return stack, but the second copy is still unavoidable.
            Personally, I think the copy issue is no big deal since exceptions are by definition supposed to be, well, exceptional—that is, they don't happen often. For most applications, the time required to copy a few bytes is, to understate the case, insignificant. But there's a more serious problem with catching by value: it's called the slicing problem. I'm not talking about Ginsu knives, I'm talking about slicing objects.
            In the previous code, e is declared as type CException, so that's what you get. Always. When the exception-throwing code throws a CMyException (derived from CException), the code that catches the exception gets a CException. The object loses all member data and functions added by CMyException; this information is sliced off. In general, C++ polymorphism only works through a pointer to an object, not an object itself. So in the case of MFC, if the code that catches the exception attempts to call the virtual functions CException::GetErrorMessage or ReportError, the compiler generates a call to CExeption::GetErrorMessage, not CMyException::GetErrorMessage—definitely not what you want.
            The only way to fix this would be to declare e as CMyException.
            														 catch (CMyException e) {     // handle it  }  
            												
            But this is obviously no solution; what happens when you introduce CMyException2? You have to modify every place that catches exceptions of this type, which rather defeats the whole purpose of polymorphism. For this reason, throwing exceptions by value is exceptionally grody.
            As you may have guessed (you're so shrewd), I've saved the best option for last: throw/catch by reference. Using references, you can still throw the exception by value
            														 throw CMyException(...);  
            												
            but now you use a reference to catch it:
            														 catch (CException& e) {     // handle it  }  
            												
            Instead of copying the thrown object into a local variable, the compiler lets the code catching the exception manipulate the stack copy directly. There's no slicing problem. Throwing/catching exceptions by reference has the best of all worlds: no extra copying, you don't have to worry about who destroys the exception object (since it's always passed on the stack), and polymorphism is preserved. So from a purely theoretical perspective, references are the best way to do exceptions.
            So much for theory. Now let's enter the world of MFC. MFC has its own exception mechanism that's based on C++, looks like C++, but isn't C++. Here you find TRY, END_TRY, CATCH, CATCH_ALL, AND_CATCH, END_CATCH, and other macros that resemble the C++ keywords.
            Let's take a look at a vanilla TRY/CATCH sequence in MFC:
            														 TRY     DoSomething(); CATCH (CMyException, e)     HandleBadKarma(); END_CATCH  
            												
            How does the compiler expand this? Don't bother going to the header files; I'll show you right now.
            														 // TRY expands to: { AFX_EXCEPTION_LINK _afxExceptionLink; try {     DoSomething(); // CATCH expands to: } catch (CMyException* e)     { ASSERT_KINDOF(CMyException, e);       _afxExceptionLink.m_pException = e;        HandleBadKarma(); // END_CATCH expands to:    } }  
            												
            The first thing you'll notice is that MFC always catches exceptions by pointer (and throws them that way too, naturally). But what's that strange AFX_EXCEPTION_ LINK object, _afxExceptionLink? It's a little object that holds a pointer to the exception. When MFC catches the exception, it sets _afxExceptionLink.m_pException to point to the caught exception. And, as you might have guessed, the destructor AFX_EXCEPTION_LINK::~AFX_EXCEPTION_LINK deletes the object. It doesn't do it directly, but calls another function, AfxTryCleanup:
            														 // called from ~AFX_EXCEPTION_LINK void AFXAPI AfxTryCleanup() {     AFX_EXCEPTION_CONTEXT* pContext         = AfxGetExceptionContext();     AFX_EXCEPTION_LINK* pLinkTop         = pContext->m_pLinkTop;       // delete current exception     if (pLinkTop->m_pException != NULL)         pLinkTop->m_pException->Delete();       // remove ourself from the top of the chain     pContext->m_pLinkTop = pLinkTop->m_pLinkPrev;  }  
            												
            The linked list of AFX_EXCEPTION_LINKs forms a stack. One global AFX_EXCEPTION_CONTEXT holds the pointer to the AFX_EXCEPTION_LINK on the top of the stack (m_pLinkTop). The AFX_EXCEPTION_LINK constructor adds itself to the stack; the destructor removes itself and deletes the exception object by calling m_pException->Delete. The upshot is this: MFC exceptions delete themselves as long as you use CATCH. Contrary to what you might expect, CException::Delete is not a virtual function; it's a normal member function that calls delete.
            														 void CException::Delete() {     if (m_bAutoDelete > 0)        delete this;  }  
            												
            By default, exceptions are auto-deleting; that is, m_bAutoDelete is TRUE. If you don't want the catch code to delete your exception—for example, if it's a static object as in the previous examples—you can change m_bAutoDelete.
            														 static CMyException staticex();  
            												
            														 staticex.m_bAutoDelete = FALSE; throw &staticex;  
            												
            Now CATCH code all over the world will not delete staticex. You can set m_bAutoDelete for a class or for an individual object, but you're forever locked into using the MFC CATCH, not the C++ catch. I won't bother to explain all the varieties of CATCH_ALL, AND_CATCH, THROW_LAST, and so on, since once you understand the idea of using AFX_EXCEPTION_LINK, you can pretty well figure out how they work.
            Why does MFC do all this magic? Mostly for historical reasons. The Microsoft
            ? compiler was slow to support C++ exceptions using try/catch, so MFC provided its roll-yer-own implementation using TRY/CATCH, which was originally implemented using C setjmp/longjmp. For backward compatibility, you can still use this implementation by #defining the symbol _AFX_OLD_EXCEPTIONS before #including <afx.h>.
            By now I've answered your question. The MFC sample code doesn't delete the exceptions because the TRY/CATCH code is so clever it generates code to delete them for you. But if you're reading the source code for MFC itself, you may be confused by code like this:
            														 TRY {     DoSomething();  } CATCH_ALL(e) {     // handle it     DELETE_EXCEPTION(e);  }  
            												
            What's DELETE_EXCEPTION? I can't explain any better than the MFC source code itself, which contains the following comment in stdafx.h: "MFC does not rely on auto-delete semantics of the TRY/CATCH macros, therefore those macros are mapped to something closer to the native C++ exception handling mechanism when building MFC itself."
            The stdafx.h used to build MFC contains its own entirely different definitions for TRY, CATCH, and so on; ones that map more or less directly to try/catch (with some ASSERTs thrown in for good measure). Since these internal TRY/CATCH implementations don't have the magic delete code, DELETE_EXCEPTION is required to manually call e->Delete.
            So there are three possible implementations of TRY/CATCH: the "normal" implementation you get without doing anything (with all the magic auto-delete stuff using AFX_EXCEPTION_LINK); the "old" backward-compatible setjmp/longjmp implementation you get when you #define _AFX_OLD_EXCEPTIONS; and the implementation MFC uses internally, which requires DELETE_EXCEPTION to delete the exceptions. If all this makes you want to throw up your hands and pull out your hair, I can sympathize. It would be nice if the folks in Redmond rationalized their exception handling to map TRY/CATCH directly to try/catch, but I don't think it will happen since that might break lots of existing code.
            So what should you do? If you call an MFC function that can throw an exception, you have no choice but to try to catch it. If you have old code that already uses TRY/CATCH, it probably works fine and you shouldn't do anything. But if you're writing new code, I would avoid TRY/CATCH entirely and stick with try/catch. Why? Three reasons: first, try/catch produces smaller code than the MFC macros (no hidden local objects with constructor/destructor calls); second, CATCH limits you to catching CException-derived exceptions; and finally, it just plain looks better to use real C++. TRY/CATCH was always a temporary kludge, so the sooner you forget it, the better. The only catch is, if you use try/catch, you have to remember to delete your exception object!
            														 try{   CallSomeMFCFunction(); } catch( CException*e) { // recover e->Delete();
            												
            轉(zhuǎn)載自Microsoft Systems Journal 1999

            posted on 2007-09-29 00:34 旅途 閱讀(597) 評(píng)論(0)  編輯 收藏 引用 所屬分類: C/C++

            天堂久久天堂AV色综合| 亚洲国产精品热久久| 久久九九免费高清视频| 国产三级精品久久| 无码人妻少妇久久中文字幕 | 久久久精品视频免费观看 | 久久精品国产亚洲av麻豆色欲 | 日本免费一区二区久久人人澡 | 99精品国产99久久久久久97 | 国产免费久久精品99re丫y| 亚洲成av人片不卡无码久久| 色综合久久无码五十路人妻| 久久亚洲国产中v天仙www| 一本久久综合亚洲鲁鲁五月天| 久久人妻无码中文字幕| 久久免费小视频| 色综合久久无码中文字幕| 久久精品免费大片国产大片| 国内精品久久久久影院日本| 国产精品xxxx国产喷水亚洲国产精品无码久久一区 | 韩国无遮挡三级久久| 久久人妻无码中文字幕| 久久国产美女免费观看精品| 久久亚洲精品中文字幕| 热99RE久久精品这里都是精品免费 | 国产日韩欧美久久| 久久香蕉国产线看观看99| 久久精品国产乱子伦| 老司机午夜网站国内精品久久久久久久久| 麻豆成人久久精品二区三区免费| 国产福利电影一区二区三区久久久久成人精品综合 | 久久人人爽人人爽人人片AV麻豆| 日本强好片久久久久久AAA| 亚洲精品视频久久久| 青青热久久国产久精品 | 久久久久久综合一区中文字幕| 国内精品九九久久精品| 精品久久久久成人码免费动漫| 久久无码一区二区三区少妇| 国产成人精品久久综合| 色播久久人人爽人人爽人人片aV|