Thomas Sampson

CallOnce

Leave a comment

UPDATE: Modified the implementation to use singleton method access to CallOnce function map. Also added example of usage distributed across multiple source files.

CallOnce is a C++ technique I have picked up recently which allows code to be executed (usually to perform static initialisation or other housekeeping activities) before the program entry point (usually main). Rather than having some Init() method right at the beginning of the application which attempts to initialise all your static objects and data, the CallOnce mechanism allows each cpp file to register it’s own functions which gets called during global static initialisation (before the program entry point). This system is much cleaner and easier to manage, removing the requirement for a large central “Init()” function.

CallOnce can be implemented in various ways. In C++ global static initialisation order is undefined, for this reason additional levels of control can be added to the CallOnce implementation to define the order in which the registered functions get called (very important if there are dependencies between static objects and data). In this post I will keep things as simple as possible and use a couple of examples to demonstrate this technique.

Example 1

In this simple example a class “CallOnce” has a constructor which takes a function pointer (return type void, no parameters). In the constructor of the CallOnce class the function passed in gets called.
To use this system all that is required is to create some global instance of the CallOnce object and pass it the address of an initialisation function (in this case ::Init). The output proves that the Init function was in fact called before the program reached main.

Main.cpp

#include <stdio.h>

class CallOnce
{
	public:
		typedef void (*CallOnceFunc)(void);
		explicit CallOnce(CallOnceFunc func)
		{ func(); }
};

void Init()
{
	printf("Hello ");
}

const CallOnce gCallOnce( &Init);
int main(int argc, char* argv[])
{
	printf("World");
	return 0;
}

Output


> Hello World

Example 2

In this slightly more involved example, rather than immediately calling the function passed in the constructor, the function is inserted into a static map and stored there until CallOnce::Init() is called. When this happens, all of the registered functions get called in order of their priority (as std::map is automatically ordered by key and we store the priority value as the map key). By default all registering functions are given priority 1000 unless the overloaded constructor is used to specify a priority (in this system 0 = Highest priority). In the example shown below, even though Init1 is registered before Init2, due to the priorities specified they are executed in reverse order.

NOTE: The CallOnce instances do not all have to exist right before main, they can be scattered around your code base inside any cpp file you want.

CallOnce.h

#include <stdio.h>
#include <map>

class CallOnce
{
	public:
		typedef void (*CallOnceFunc)(void);
		typedef std::map<int, CallOnceFunc> FuncMap;

		explicit CallOnce(CallOnceFunc func)
		{
			static const unsigned int uDefaultPriority = 1000;
			GetFuncMap().insert(std::make_pair<int,CallOnceFunc>(uDefaultPriority, func));
		}
		explicit CallOnce(CallOnceFunc func, int iPriority)
		{
			GetFuncMap().insert(std::make_pair<int,CallOnceFunc>(iPriority, func));
		}
		static void Init()
		{
			FuncMap::const_iterator it(GetFuncMap().begin());
			for(; it != GetFuncMap().end(); ++it)
				(*it).second();
		}
	private:
		static FuncMap& GetFuncMap()
		{
			static FuncMap singleton;
			return singleton;
		}
};

Foo.cpp

#include "CallOnce.h"

void Init1() { printf("Init1 Called\r\n"); }
const CallOnce gCallOnce	 ( &Init1, 1);

Bar.cpp

#include "CallOnce.h"

void Init2() { printf("Init2 Called\r\n"); }
const CallOnce gCallOnceAgain( &Init2, 0);

Main.cpp

#include "CallOnce.h"

int main(int argc, char* argv[])
{
	CallOnce::Init();
	printf("Main Called");
	return 0;
}

Output


> Init2 Called

> Init1 Called

> Main Called

Advertisements

Author: tomtech999

I have recently graduated with a 1st class degree in MComp Games Software Development at Sheffield Hallam University, focusing primarily on application development in C++, with experience in graphics programming, scripting languages, DVCS/VCS and web technology. In my spare time I enjoy Drumming, Reading and Snowboarding!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s