From 3bcec846a072e304b809bd2a0311db1e5083700d Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 24 Aug 2014 15:31:52 +0000 Subject: [PATCH] Provide wxApp::StoreCurrentException() implementation for C++11. When using C++11 we can provide implementations of wxApp::StoreCurrentException() and RethrowStoredException() ourselves and thus make catching exceptions outside of the event loop work by default. Do this and update the documentation and the sample to reflect it. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@77470 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- docs/changes.txt | 3 +- docs/doxygen/overviews/exceptions.h | 17 ++++---- include/wx/app.h | 21 +++++++--- interface/wx/app.h | 14 +++++++ samples/except/except.cpp | 4 ++ src/common/appbase.cpp | 60 +++++++++++++++++++++++++++-- 6 files changed, 102 insertions(+), 17 deletions(-) diff --git a/docs/changes.txt b/docs/changes.txt index a28a707bf6..90b4bf972f 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -32,7 +32,8 @@ Changes in behaviour which may result in build errors All: -- Add wxApp::StoreCurrentException() and RethrowStoredException(). +- Add wxApp::StoreCurrentException() and RethrowStoredException() and implement + their functionality by default when using C++11 compiler. - Allow iterating over wxCmdLineParser arguments in order (Armel Asselin). - Add wxScopedArray ctor taking the number of elements to allocate. - Add wxDynamicLibrary::GetModuleFromAddress() (Luca Bacci). diff --git a/docs/doxygen/overviews/exceptions.h b/docs/doxygen/overviews/exceptions.h index 2682020182..e4f0e3395c 100644 --- a/docs/doxygen/overviews/exceptions.h +++ b/docs/doxygen/overviews/exceptions.h @@ -97,13 +97,16 @@ void TestNewDocument() } @endcode -Unfortunately, by default this example does @e not work because an exception -can't be safely propagated back to the code handling it in @c TestNewDocument() -through the system event dispatch functions which are not compatible with C++ -exceptions. Because of this, you need to override wxApp::StoreCurrentException() -and wxApp::RethrowStoredException() to help wxWidgets to safely transport the -exception from the event handler that throws it to the @c catch clause. Please -see the documentation of these functions for more details. +Unfortunately, by default this example only works when using a C++11 compiler +because the exception can't be safely propagated back to the code handling it +in @c TestNewDocument() through the system event dispatch functions which are +not compatible with C++ exceptions and needs to be stored by wxWidgets when it +is first caught and rethrown later, when it is safe to do it. And such storing +and rethrowing of exceptions is only possible in C++11, so while everything +just works if you do use C++11, there is an extra step if you are using C++98: +In this case you need to override wxApp::StoreCurrentException() and +wxApp::RethrowStoredException() to help wxWidgets to do this, please see the +documentation of these functions for more details. @section overview_exceptions_tech Technicalities diff --git a/include/wx/app.h b/include/wx/app.h index bfed781ac6..af86beb0d2 100644 --- a/include/wx/app.h +++ b/include/wx/app.h @@ -306,16 +306,25 @@ public: // This function can be overridden to store the current exception, in view // of rethrowing it later when RethrowStoredException() is called. If the - // exception was stored, return true. The default implementation returns - // false, indicating that the exception wasn't stored and that the program - // should be simply aborted. + // exception was stored, return true. If the exception can't be stored, + // i.e. if this function returns false, the program will abort after + // calling OnUnhandledException(). + // + // The default implementation of this function when using C++98 compiler + // just returns false, as there is no generic way to store an arbitrary + // exception in C++98 and each application must do it on its own for the + // exceptions it uses in its overridden version. When using C++11, the + // default implementation uses std::current_exception() and returns true, + // so it's normally not necessary to override this method when using C++11. virtual bool StoreCurrentException(); // If StoreCurrentException() is overridden, this function should be // overridden as well to rethrow the exceptions stored by it when the - // control gets back to our code, i.e. when it's safe to do it. The default - // version does nothing. - virtual void RethrowStoredException() { } + // control gets back to our code, i.e. when it's safe to do it. + // + // The default version does nothing when using C++98 and uses + // std::rethrow_exception() in C++11. + virtual void RethrowStoredException(); #endif // wxUSE_EXCEPTIONS diff --git a/interface/wx/app.h b/interface/wx/app.h index b247efa38e..546731b58a 100644 --- a/interface/wx/app.h +++ b/interface/wx/app.h @@ -486,6 +486,14 @@ public: /** Method to store exceptions not handled by OnExceptionInMainLoop(). + @note The default implementation of this function when using C++98 + compiler just returns false, as there is no generic way to store an + arbitrary exception in C++98 and each application must do it on its + own for the exceptions it uses in its overridden version. When + using C++11, the default implementation uses + std::current_exception() and returns true, so it's normally not + necessary to override this method when using C++11. + This function can be overridden to store the current exception, in view of rethrowing it later when RethrowStoredException() is called. If the exception was stored, return true. If the exception can't be stored, @@ -572,12 +580,18 @@ public: /** Method to rethrow exceptions stored by StoreCurrentException(). + @note Just as with StoreCurrentException(), it is usually not necessary + to override this method when using C++11. + If StoreCurrentException() is overridden, this function should be overridden as well to rethrow the exceptions stored by it when the control gets back to our code, i.e. when it's safe to do it. See StoreCurrentException() for an example of implementing this method. + The default version does nothing when using C++98 and uses + std::rethrow_exception() in C++11. + @since 3.1.0 */ virtual void RethrowStoredException(); diff --git a/samples/except/except.cpp b/samples/except/except.cpp index 0fb1f55d5f..8475a1ea49 100644 --- a/samples/except/except.cpp +++ b/samples/except/except.cpp @@ -94,6 +94,10 @@ public: // 2nd-level exception handling helpers: if we can't deal with the // exception immediately, we may also store it and rethrow it later, when // we're back from events processing loop. + // + // Notice that overriding these methods is not necessary when using C++11 + // as they have a perfectly serviceable implementation inside the library + // itself in this case. virtual bool StoreCurrentException() wxOVERRIDE; virtual void RethrowStoredException() wxOVERRIDE; diff --git a/src/common/appbase.cpp b/src/common/appbase.cpp index 164a33c6fc..58fe2b2e3e 100644 --- a/src/common/appbase.cpp +++ b/src/common/appbase.cpp @@ -46,12 +46,28 @@ #include "wx/tokenzr.h" #include "wx/thread.h" -#if wxUSE_STL - #if wxUSE_EXCEPTIONS +#if wxUSE_EXCEPTIONS + // Do we have a C++ compiler with enough C++11 support for + // std::exception_ptr and functions working with it? + #if __cplusplus >= 201103L + // Any conforming C++11 compiler should have it. + #define HAS_EXCEPTION_PTR + #elif wxCHECK_VISUALC_VERSION(10) + // VC++ supports it since version 10, even though it doesn't define + // __cplusplus to C++11 value. + #define HAS_EXCEPTION_PTR + #endif + + #ifdef HAS_EXCEPTION_PTR + #include // for std::current_exception() + #include // for std::swap() + #endif + + #if wxUSE_STL #include #include #endif -#endif // wxUSE_STL +#endif // wxUSE_EXCEPTIONS #if !defined(__WINDOWS__) || defined(__WXMICROWIN__) #include // for SIGTRAP used by wxTrap() @@ -659,11 +675,49 @@ bool wxAppConsoleBase::OnExceptionInMainLoop() throw; } +#ifdef HAS_EXCEPTION_PTR +static std::exception_ptr gs_storedException; + +bool wxAppConsoleBase::StoreCurrentException() +{ + if ( gs_storedException ) + { + // We can't store more than one exception currently: while we could + // support this by just using a vector, it shouldn't be + // actually necessary because we should never have more than one active + // exception anyhow. + return false; + } + + gs_storedException = std::current_exception(); + + return true; +} + +void wxAppConsoleBase::RethrowStoredException() +{ + if ( gs_storedException ) + { + std::exception_ptr storedException; + std::swap(storedException, gs_storedException); + + std::rethrow_exception(storedException); + } +} + +#else // !HAS_EXCEPTION_PTR + bool wxAppConsoleBase::StoreCurrentException() { return false; } +void wxAppConsoleBase::RethrowStoredException() +{ +} + +#endif // HAS_EXCEPTION_PTR/!HAS_EXCEPTION_PTR + #endif // wxUSE_EXCEPTIONS // ----------------------------------------------------------------------------