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:
- 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).

View File

@ -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

View File

@ -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

View File

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

View File

@ -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;

View File

@ -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 <exception> // for std::current_exception()
#include <utility> // for std::swap()
#endif
#if wxUSE_STL
#include <exception>
#include <typeinfo>
#endif
#endif // wxUSE_STL
#endif // wxUSE_EXCEPTIONS
#if !defined(__WINDOWS__) || defined(__WXMICROWIN__)
#include <signal.h> // 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<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()
{
return false;
}
void wxAppConsoleBase::RethrowStoredException()
{
}
#endif // HAS_EXCEPTION_PTR/!HAS_EXCEPTION_PTR
#endif // wxUSE_EXCEPTIONS
// ----------------------------------------------------------------------------