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
This commit is contained in:
Vadim Zeitlin
2014-08-24 15:31:52 +00:00
parent 73aea138c6
commit 3bcec846a0
6 changed files with 102 additions and 17 deletions

View File

@@ -32,7 +32,8 @@ Changes in behaviour which may result in build errors
All: 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). - Allow iterating over wxCmdLineParser arguments in order (Armel Asselin).
- Add wxScopedArray ctor taking the number of elements to allocate. - Add wxScopedArray ctor taking the number of elements to allocate.
- Add wxDynamicLibrary::GetModuleFromAddress() (Luca Bacci). - Add wxDynamicLibrary::GetModuleFromAddress() (Luca Bacci).

View File

@@ -97,13 +97,16 @@ void TestNewDocument()
} }
@endcode @endcode
Unfortunately, by default this example does @e not work because an exception Unfortunately, by default this example only works when using a C++11 compiler
can't be safely propagated back to the code handling it in @c TestNewDocument() because the exception can't be safely propagated back to the code handling it
through the system event dispatch functions which are not compatible with C++ in @c TestNewDocument() through the system event dispatch functions which are
exceptions. Because of this, you need to override wxApp::StoreCurrentException() not compatible with C++ exceptions and needs to be stored by wxWidgets when it
and wxApp::RethrowStoredException() to help wxWidgets to safely transport the is first caught and rethrown later, when it is safe to do it. And such storing
exception from the event handler that throws it to the @c catch clause. Please and rethrowing of exceptions is only possible in C++11, so while everything
see the documentation of these functions for more details. 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 @section overview_exceptions_tech Technicalities

View File

@@ -306,16 +306,25 @@ public:
// This function can be overridden to store the current exception, in view // This function can be overridden to store the current exception, in view
// of rethrowing it later when RethrowStoredException() is called. If the // of rethrowing it later when RethrowStoredException() is called. If the
// exception was stored, return true. The default implementation returns // exception was stored, return true. If the exception can't be stored,
// false, indicating that the exception wasn't stored and that the program // i.e. if this function returns false, the program will abort after
// should be simply aborted. // 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(); virtual bool StoreCurrentException();
// If StoreCurrentException() is overridden, this function should be // If StoreCurrentException() is overridden, this function should be
// overridden as well to rethrow the exceptions stored by it when the // 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 // control gets back to our code, i.e. when it's safe to do it.
// version does nothing. //
virtual void RethrowStoredException() { } // The default version does nothing when using C++98 and uses
// std::rethrow_exception() in C++11.
virtual void RethrowStoredException();
#endif // wxUSE_EXCEPTIONS #endif // wxUSE_EXCEPTIONS

View File

@@ -486,6 +486,14 @@ public:
/** /**
Method to store exceptions not handled by OnExceptionInMainLoop(). 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 This function can be overridden to store the current exception, in view
of rethrowing it later when RethrowStoredException() is called. If the of rethrowing it later when RethrowStoredException() is called. If the
exception was stored, return true. If the exception can't be stored, exception was stored, return true. If the exception can't be stored,
@@ -572,12 +580,18 @@ public:
/** /**
Method to rethrow exceptions stored by StoreCurrentException(). 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 If StoreCurrentException() is overridden, this function should be
overridden as well to rethrow the exceptions stored by it when the 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. control gets back to our code, i.e. when it's safe to do it.
See StoreCurrentException() for an example of implementing this method. 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 @since 3.1.0
*/ */
virtual void RethrowStoredException(); virtual void RethrowStoredException();

View File

@@ -94,6 +94,10 @@ public:
// 2nd-level exception handling helpers: if we can't deal with the // 2nd-level exception handling helpers: if we can't deal with the
// exception immediately, we may also store it and rethrow it later, when // exception immediately, we may also store it and rethrow it later, when
// we're back from events processing loop. // 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 bool StoreCurrentException() wxOVERRIDE;
virtual void RethrowStoredException() wxOVERRIDE; virtual void RethrowStoredException() wxOVERRIDE;

View File

@@ -46,12 +46,28 @@
#include "wx/tokenzr.h" #include "wx/tokenzr.h"
#include "wx/thread.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 <exception> // for std::current_exception()
#include <utility> // for std::swap()
#endif
#if wxUSE_STL
#include <exception> #include <exception>
#include <typeinfo> #include <typeinfo>
#endif #endif
#endif // wxUSE_STL #endif // wxUSE_EXCEPTIONS
#if !defined(__WINDOWS__) || defined(__WXMICROWIN__) #if !defined(__WINDOWS__) || defined(__WXMICROWIN__)
#include <signal.h> // for SIGTRAP used by wxTrap() #include <signal.h> // for SIGTRAP used by wxTrap()
@@ -659,11 +675,49 @@ bool wxAppConsoleBase::OnExceptionInMainLoop()
throw; 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<exception_ptr>, 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() bool wxAppConsoleBase::StoreCurrentException()
{ {
return false; return false;
} }
void wxAppConsoleBase::RethrowStoredException()
{
}
#endif // HAS_EXCEPTION_PTR/!HAS_EXCEPTION_PTR
#endif // wxUSE_EXCEPTIONS #endif // wxUSE_EXCEPTIONS
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------