According to what I have learnt so far, instantiating global objects should
be the last resort. Is there any reasons why so?
Another reason, apart from what was already mentioned, is order of
initialisation. Globals in one source file are initialised in the order
they are declared, but in what order the source files are initialised is
undefined.
For small projects, you probably could'nt care less, but for larger
programs, this quickly becomes a nightmare.
Sometimes some objects or their pointers have to be shared among several
other objects, I'd like to know how this is handled commonly. Could
someone elaborate on this?
There are many ways, depending on your situation.
1) Redesign. Do you really need it? Is it not just bad design?
2) Ask yourself, what concept does this global represent? Create a class
that represents the concept, never use raw pointers or other values as
globals. Often you'll find you can cluster groups of former globals behind
one interface, using only one global of this new class (also see point 4).
3) Use a singleton. Search google for more info, there are litterally
hunderds of ways how toimplement this in C++.
One way would be:
template<typename T>
class Singleton {
static T& instance() {
static T inst;
return instance;
}
};
Use as follows:
//instantiate as a global:
Singleton<myclass> mysingleton;
// use the object:
void f() {
mysingleton::instance().doSomething();
}
4) Pass around as parameters. Often some (former) globals can be grouped
into one class and a pointer to an object of this class can be passed
around. Obviously these objects should be related and should have been
grouped in a class anyhow. This strongly relates to point 2.
5) If it has to be shared between similar objects, does a common baseclass
help? Maybe containing a static? Or containing a pointer to whatever they
all need access to? Again, think in concepts, not in implementations. A
good concept will (often, not always) spell out the (correct)
implementation.
6) Create one 'god' class that contains all the globals, and only make
that global, or make it a singleton. This is often a sign of bad design,
but...
7) ... call that god class Application and you have a very common
framework setup.
Something I sometimes do (using another form of singleton):
class MyApp {
public:
MyApp();
int run(int argc, char **argv);
static MyApp& instance() { return *inst_; }
// Other member functions here
private:
MyApp *inst_;
// other data members here
};
MyApp::MyApp()
{
assert(!inst_);
inst_ = this;
}
int main(int argc, char **argv)
{
try {
return MyApp().run(argc, argv);
} catch (const ....) {
// lots of error handling here for runaway exceptions
}
}
// somehwere else
void DeepDown::somewhereintheprogram()
{
// how we warn depends on how the program is invoked.
MyApp::instance().emitWarning(...);
...
}
Another situation is some objects could be shared among several threads.
How to handle it commonly?
Use any of the ways given above, but with threads it is even more
important to limit the use of globals. I most often use stack based
objects created somewhere in main or quickly after that, so they stay in
scope for the lifetime of the program. By passing the right arguments to
the threads the threads have pointers to these objects. Obviously these
objects should have ways to synchronize access to them. Also obviously,
you should make sure all subthreads have exited before these objects pass
out of scope.
Whatever you do, in the face of threads you want your accesses to be
tightly controlled. This means wrapping everything in classes that govern
the synchronization for access. Wether this is a global, a singleton or
whatever does not matter. Multi-threaded programming can be hard, but
mainly because programmers don't follow the above advice. If you do it the
way I say here, thread based programming suddenly ceases to be the big
problem it is often said to be! (But note that this is OT for this group!)
HTH,
M4