Wednesday, December 20, 2006

Thunking in Win32, at Codeproject.com

I posted the Thunking in win32 article at Codeproject the other day (http://www.codeproject.com/useritems/thunk32.asp), and has gotten valuable response. As a result, I've further adapted the library, with even more changes to come in the future, such as:

  • x64 support.
  • Proper allocation pools, to avoid large memory use when a (very) high number of thunks is used.
  • Possibly support for even more calling conventions.
When I first posted the article, I feel that I got some undeserved low votes. Not that the voting matters that much, but when you're given multiple 1's from someone who don't even bother to read the full article (let alone view the source); that's frustrating. A few seemed to think that I was presenting another boost::function replacement, which I by no means am. The article and library describes a way to convert between calling conventions, in all its simplicity, and is definitely not a functor replacement :)

Thursday, December 14, 2006

All work and no updates, but exceptions are hooked!

I'm having a busy couple of weeks, so apart from publishing the ThreadSynch library + article, I haven't found time to add any new content here. I've got a deadline set next tuesday, so unless I manage to power through all the work over the next few days, I doubt that anything new will be added till then. I do have a few writings in the pipeline, though, including an update of the Thunk32 library + article.

In the mean time, I'd love it if those who take the time to read through the ThreadSynch library give me their take on the subject, either from personal experience with similar cases, or merely immediate thoughts on my text.

If you've got no interest (or just haven't found time) to look at the ThreadSynch source, I'll pull up this construct to get you started:
template<class T>
void throwHooked(const T& orig, boost::function<void()>& onDeathFunctor)
{
#pragma warning(push)
#pragma warning(disable: 4512)
class ExHook : public T
{
public:
ExHook(const T& other, const boost::function<void()>& onDeathFunctor)
: T(other),
m_onDeathFunctor(onDeathFunctor)
{}

ExHook(const ExHook& other)
: T(other),
m_onDeathFunctor(other.m_onDeathFunctor)
{}

~ExHook()
{ m_onDeathFunctor(); }

private:
const boost::function<void()> m_onDeathFunctor;
};
#pragma warning(pop)

throw ExHook(orig, onDeathFunctor);
}
It's essentially a utility function which wraps an exception object with a functor to be executed when the exception object is destroyed. Possible use? You tell me. I came up with it in the ThreadSynch library to control the life span of state data, in case of exceptions being re-thrown across the threads.

The curious thing is that you wouldn't want to write such generic wrappers if it weren't to bind to a thrown object. With the rules of polymorphism in mind, a base object with a non-virtual destructor, referenced or pointed to by base class, will not have it's derived destructors executed as the object is destroyed. This is not the case with thrown objects which are free'd by the exception mechanism. If you throw a class type, it will be destroyed in context of the thrown type -- even if caught by base type.

This all makes perfect sense for catch-by-reference, but it's also the case for objects caught-by-value. Why? It's the effect of slicing and the stack unwind. When a by-value catch handler is found, a sliced (derived classes stripped) copy of the catch-type will be copy-constructed into place. This sliced copy will be destroyed at the end of the catch block, and will obviously not execute of the functor, since the derived class has been removed. Shortly thereafter, the original exception object will be destroyed in the final phase of the stack unwind. This last object will be destroyed in context of the thrown type, and therefore call the functor.

Ok, so what about return value optimization (RVO), or named return value optimization (NRVO)? Couldn't a catch-by-value lead to the constructor constructing a sliced object directly into place in the catch handler? A behaving compiler will not omit the use of a temporary object when the type thrown is not the same as that caught, so no -- this is not a problem. Thanks for asking, though :]

Monday, December 11, 2006