Global objects...

P

Phlip

barcaroller said:
What is the proper way to instantiate a global object that is visible to
all
modules in a project?

Look up the "singleton pattern" for C++.

If you write this...

Global aGlobal;

....then code in other "modules" (translation units) that evaluates before
main() might access aGlobal. C++ cannot guarantee the order of
initialization of global objects.

The fix is this:

Global &getGlobal()
{
static Global aGlobal;
return aGlobal;
}

A static at function scope is guaranteed to initialize before its first use.
Currently, I instantiate the object in one module
and then use 'extern' in a header file which is "included" in all modules,
but I wonder whether this is the best way.

That's the unsafe way, but it's only unsafe if you write clever clever code,
such as other global constructors, that call before main().

Next, you should not treat this object as a global, even if it lives longer
than main(). All your methods should not just reach out and grab it; that
makes your code hard to upgrade, hard to decouple from this object, and
hard to unit test. Your top-level methods should pass values from this
global into their called methods, and these should only rely on the passed
values.
 
B

barcaroller

What is the proper way to instantiate a global object that is visible to all
modules in a project? Currently, I instantiate the object in one module and
then use 'extern' in a header file which is "included" in all modules, but I
wonder whether this is the best way.
 
A

Alf P. Steinbach

* barcaroller:
What is the proper way to instantiate a global object that is visible to all
modules in a project? Currently, I instantiate the object in one module and
then use 'extern' in a header file which is "included" in all modules, but I
wonder whether this is the best way.

Read the FAQ on global initialization order fiasco, and Google for
Meyer's singleton.

Cheers, & hth.,

- Alf
 
W

werasm

Phlip said:
Your top-level methods should pass values from this
global into their called methods, and these should only rely on the passed
values.

Yes, Phlip (generally value your thoughts, BTW). That was always the
way I've
done it, usually using either constructor parameters or methods like
<associate>
or <adopt>, depending on circumstance... But I've found that I write a
lot of
code that has just that purpose. Also note that Singleton is not good
enough,
as Singleton binds you to implementation (most often), except if the
Singleton's
implementation hides behind a pimpl, but that does not necessarily
allow
polymorphism, although I suppose you could get polymorphism by using
the
bridge pattern - having concrete relationships, these making use of
factories
to achieve what is required. Hmmm, Singletons that make use of
factories to
achieve polymorphism. I suppose that is a solution, yes. OTOH
factories
tend to get sooo complex...

I suppose you could make more valuable contributions (any other
ideas?).
Another idea that struck me was the idea of a Singleton interface, but
no
one seemed to like the idea. I suppose it is too intrusive. It boils
down to this:

#include <cassert>
#include <boost/noncopyable.hpp>

class SingleIFBase : boost::noncopyable
{
protected:
enum eAction{ eCreate, eDestroy, eGet };
};

template <class T>
class SingleIF : SingleIFBase
{
public:
static T& get();

protected:
SingleIF( T& impl );
~SingleIF();

private:
static T* doAction( eAction, T* impl = 0 );
};

//
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
template <class T>
T* SingleIF<T>::doAction( eAction action, T* impl )
{
static SingleIF* inst( 0 );
if( action == eGet )
{
assert( inst );
}
else if( action == eCreate )
{
assert( inst == 0 );
inst = impl;
}
else
{
assert( action == eDestroy );
assert( inst );
inst = 0;
}
return static_cast<T*>(inst);
}
//
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
template <class T>
SingleIF<T>::SingleIF( T& impl )
{
SingleIF::doAction( eCreate, &impl );
}
//
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
template <class T>
SingleIF<T>::~SingleIF()
{
SingleIF::doAction( eDestroy );
}
//
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
template <class T>
T& SingleIF<T>::get()
{
return (*SingleIF::doAction( eGet ) );
}

.... and is usually used like this (This is an interface
specification):

class MyInterface : public SingleIF<MyInterface>
{
public:
virtual void method1() = 0;
virtual void method2() = 0;
virtual void method3() = 0;

protected:
~MyInterface(){ } //Could be virtual to prohibit compiler warnings
MyInterface(): SingleIF( *this ){ }
};

BTW, I know it does have some caveats that I can think of (slicing at
the
end of its life (an obvious one) ), but in general it seems to reduce
all this
associative code required to get the right "concrete" at the right
place. For
me it seems a simpler solution than factories and in general it works
very well, especially if you want only one instance (or
implementation) of
an interface - something that I've seemed to require often.

Regards,

Werner
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top