Boost Exception and support for cloning

In the Boost Exception review process, several people have expressed the opinion that since boost::exception (part of the proposed library) is designed to act as a base class for all Boost exceptions, it should also support cloning. This can be done by adding a clone() virtual function to boost::exception. There are several issues we have to consider. First, should clone() be pure virtual, which would require all deriving exceptions to implement it? This can be achieved by modifying boost::throw_exception to throw a type that derives from the passed exception type and implements clone(). If we go that route, we must make sure that Boost does not contain a "naked" throw statement (that is, a throw that does not call boost::throw_exception.) This should be fine, since Boost libraries are required to call boost::throw_exception anyway. However, the functionality provided by boost::exception would be desirable for user code as well, and thus it would make sense for user-defined exception types to derive it. Which raises my second question: should then user code also be required to throw exceptions by calling boost::throw_exception? Emil Dotchevski

This can be done by adding a clone() virtual function to boost::exception.
Since the clone function is just a stopgap until 0x, would it be better to implement it without explicitly adding the clone function to the interface? For example, use an auto-registration idiom to collect all of the exception types: void throw_exception(const E&e) { static autoregister_exception<E> registration; throw e; } Provide an implementation of "copy_exception" that searches for a type_info match. Perhaps this clumsy implementation is better than everyone ending up a few years from now with dependencies on an obsolete clone interface.
Why not throw a std::ostringstream directly then? :)
I was just trying to demonstrate that: - Tagged fields could be mixed with untagged fields to encourage more ad-hoc data in the exception (to aid debugging). - Both untagged and tagged types can be visited by the error handler in a type-safe manner. Tagging is only really required when the identity of the field would otherwise be ambiguous. - Fields from one exception object could be copied into a second. - Formatting of the "what" message can be specified inline at the throw site but remain uninterpreted until the error handler is reached. -Joshua Napoli

Mathias Gaunard wrote: C++0x has virtual constructors?
No - but exceptions (only) will get a special built-in clone mechanism (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2179.html) std::copy_exception will do the same thing that a clone member function would do. The exception library could implement copy_exception (in part) by searching a table of registered types for a match.

"Josh Napoli" <jnapoli@actuality-systems.com> writes:
Mathias Gaunard wrote: C++0x has virtual constructors?
No - but exceptions (only) will get a special built-in clone mechanism (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2179.html)
I have an implementation of this for MSVC which I intended to upload soon for boost.thread, once I'd got a generic (and thus incomplete) version working. Source code attached. Anthony -- Anthony Williams Just Software Solutions Ltd - http://www.justsoftwaresolutions.co.uk Registered in England, Company Number 5478976. Registered Office: 15 Carrallack Mews, St Just, Cornwall, TR19 7UL

Here is a generic exception_ptr implementation based on a registry of exception types. (http://joshuanapoli.com/exception/) The registry is built at runtime. boost::throw_exception can register the thrown type. current_exception() searches for the most derived type in the registry that matches the current exception. (http://joshuanapoli.com/exception/jn/boost/exception/detail/emulate_exc eption_ptr.hpp) -----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Anthony Williams Sent: Wednesday, October 24, 2007 7:26 AM To: boost@lists.boost.org Subject: Re: [boost] Boost Exception and support for cloning "Josh Napoli" <jnapoli@actuality-systems.com> writes:
Mathias Gaunard wrote: C++0x has virtual constructors?
No - but exceptions (only) will get a special built-in clone mechanism (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2179.html)
I have an implementation of this for MSVC which I intended to upload soon for boost.thread, once I'd got a generic (and thus incomplete) version working. Source code attached. Anthony -- Anthony Williams Just Software Solutions Ltd - http://www.justsoftwaresolutions.co.uk Registered in England, Company Number 5478976. Registered Office: 15 Carrallack Mews, St Just, Cornwall, TR19 7UL

Here is a generic exception_ptr implementation based on a registry of exception types. (http://joshuanapoli.com/exception/) The registry is built at runtime. boost::throw_exception can register the thrown type. current_exception() searches for the most derived type in the registry that matches the current exception. (http://joshuanapoli.com/exception/jn/boost/exception/detail/emulate_exc eption_ptr.hpp)
If boost::throw_exception is modified such that its postcondition is that the exception object it throws derives from boost::exception (I can't think of a reason not to), cloning can be implemented intrusively without a need for registration. A run-time registry maintained by boost::throw_exception could cause problems in multi-threaded environments, as well as in the presence of DLLs (consider that if a DLL is unloaded, any std::type_info object obtained from it becomes invalid, so it can not be used safely as a key in the registry.) -- Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

Here is a generic exception_ptr implementation based on a registry of exception types. (http://joshuanapoli.com/exception/) The registry is
If boost::throw_exception is modified such that its postcondition is that the exception object it throws derives from boost::exception (I can't think of a reason not to), cloning can be implemented intrusively without a need for registration.
I would hope to save exceptions thrown from 3rd party libraries. An intrusive approach wouldn't work.
A run-time registry maintained by boost::throw_exception could cause problems in multi-threaded environments, as well as in the presence of DLLs (consider that if a DLL is unloaded, any std::type_info object obtained from it becomes invalid, so it can not be used safely as a key in the registry.)
DLL unload is an interesting problem.

Here is a generic exception_ptr implementation based on a registry of exception types. (http://joshuanapoli.com/exception/) The registry is
If boost::throw_exception is modified such that its postcondition is that the exception object it throws derives from boost::exception (I can't think of a reason not to), cloning can be implemented intrusively without a need for registration.
I would hope to save exceptions thrown from 3rd party libraries. An intrusive approach wouldn't work.
For boost::throw_exception to be able to register the exception type from 3rd party libraries, they must call boost::throw_exception. If they call boost::throw_exception then we have the concrete type they wish to throw (as a template parameter) and we can wrap that type in something else which implements the cloning. This would be very similar to the current semantics of boost::enable_error_info (part of boost::exception.) -- Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

Emil Dotchevski wrote:
Here is a generic exception_ptr implementation based on a registry of exception types. (http://joshuanapoli.com/exception/) The registry is
If boost::throw_exception is modified such that its postcondition is that the exception object it throws derives from boost::exception (I can't think of a reason not to), cloning can be implemented intrusively without a need for registration.
I would hope to save exceptions thrown from 3rd party libraries. An intrusive approach wouldn't work.
For boost::throw_exception to be able to register the exception type from 3rd party libraries, they must call boost::throw_exception.
No, they don't need to call throw_exception. Registration of an exception type can occur separately from the throw. For example, a user could register an exception thrown by a binary-only library. Then current_exception() would be able to clone exceptions from the unmodified library, even if it uses a "bare" throw statement. register_exception<Lib::derived_error>(); try { //calls 'throw derived_error' and we can't change it to throw_exception Lib::raise_error(); } catch(Lib::base_error&) { transfer_to_other_thread(current_exception()); //copies derived_error } However, as you pointed out, any types registered by a DLL would need to be manually unregistered before the DLL is unloaded. This seems unacceptable. Does boost::serialization have this problem?

I would hope to save exceptions thrown from 3rd party libraries. An intrusive approach wouldn't work.
For boost::throw_exception to be able to register the exception type from 3rd party libraries, they must call boost::throw_exception.
No, they don't need to call throw_exception. Registration of an exception type can occur separately from the throw. For example, a user could register an exception thrown by a binary-only library.
Sure, but in this case registration wouldn't be automatic. I think that implementing clone() automatically at the time of the throw inside boost::throw_exception is the best approach, because the throw statement is guaranteed to see the complete type, which is required to define public no-throw copy constructor -- and this is exactly what we need to implement clone(). In this case boost::throw_exception would become more generic, in that it would not be just a mechanism for boost components to throw exceptions, but would also become a way for 3rd party code to throw exceptions such that they get automatic cloning, plus the data transporting functionality from boost::exception. -- Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

On 10/23/07, Mathias Gaunard <mathias.gaunard@etu.u-bordeaux1.fr> wrote:
Josh Napoli wrote:
This can be done by adding a clone() virtual function to boost::exception.
Since the clone function is just a stopgap until 0x
C++0x has virtual constructors?
Cloning can be supported non-intrusively, without virtual constructors or virtual clone() functions. You can have a look at the Optional Polymorphic Value object with Small Object optimization Library in the vault: *http://tinyurl.com/2og6st* The thread discussing it is: http://archives.free.net.ph/thread/20071102.211935.ab0db275.en.html The only requirement you need is that all your concrete classes derive from a know base class, and you get cloning and the small object optimization for free. Corrado _______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
-- __________________________________________________________________________ dott. Corrado Zoccolo mailto:zoccolo@di.unipi.it PhD - Department of Computer Science - University of Pisa, Italy -------------------------------------------------------------------------- The self-confidence of a warrior is not the self-confidence of the average man. The average man seeks certainty in the eyes of the onlooker and calls that self-confidence. The warrior seeks impeccability in his own eyes and calls that humbleness. Tales of Power - C. Castaneda
participants (5)
-
Anthony Williams
-
Corrado Zoccolo
-
Emil Dotchevski
-
Josh Napoli
-
Mathias Gaunard