Sunday, October 21, 2007

Lazy Initailization Idioms

Double check idiom is supposedly the best lazy initialization technique

private static Foo foo = null;

public static void getFoo(){
if (null == foo){
synchronized (Foo.class){
if ( null == foo){
foo = new Foo();
}
}
}
return foo;
}

This is the double check idiom , it works great with primitives but is flawed when it
comes to object references cause the behaviour of object references after synchronized is
undefined.

Solution 1:

private static Foo foo = new Foo();

public static void getFoo(){
return foo;
}

Solution 2:

private static Foo foo = null;

public synchronized Foo getFoo(){
if (null == Foo)
foo = new Foo();
return foo;
}

Solution 3:

Initialize on demand - holder class Idiom

private static class Holder{
static Foo foo = new Foo();
}

public static Foo getFoo(){
return Holder.foo;
}

set_new_handler in

The correct way of overriding the new operator can be something. Here i try to highlight how one can go about doing so .

typedef void (*new_handler)();


In the new header file , a typedef new handler is defined . This typedef basically refers to
the function that the new operator will call if it is not able to allocate memory properly.
Generally the new operator specification looks for the new_handler to allocate more or release
memory so that the new operator can call it properly.

new_handler set_new_handler(new_handler handler);

is a function also found in that installs the new handler . A typical implementation
of this should return the old_handler that was replaced.

The new operator throws std::bad_alloc exception when it is not able to allocate memory.

Class specific handlers can be installed for class specific new operator .
The code for managing the operator and the handler can go in one templatised base class.
Derived classes can then inherit from this class . The base class is very specialized class
as it only provides only one type of functionality.Such type of classes are called mixins.

template
class NewHandler{
public:
static new_handler set_new_handler(new_handler handler);
static void* operator new(size_t size);

private:
static new_handler currentHandler;
};

template
new_handler NewHandler::currentHandler;

template
new_handler NewHandler::set_new_handler(new_handler handler){
new_handler oldHandler = currentHandler;
currentHandler = handler;
return oldHandler;
}

template
void* NewHandler::operator new(size_t size){
new_handler globalHandler = std::set_new_handler(NewHandler::currentHandler):
void * memory;
try{
// try to allocate memory using global new operator
memory = ::operator new(size);
}catch(std::bad_alloc &){
std::set_new_handler(globalHandler);
// propogate all the exceptions
throw;
}
// reinstall the saved gloabal handler
std::set_new_handler(globalHandler);
return memory;
}

Now any class X can use NewHandler like this :

class X : public NewHandler {
};