Re: Assign Reference to another Referance
class Singleton
{
public:
static Singleton & Instance()
{
if( !m_instance )
{
m_instance = new Singleton();
}
return *m_instance;
}
static void DoStuff()
{
int x = 1 + 1;
}
private:
static Singleton * m_instance;
};
Singleton * Singleton::m_instance = 0;
class Foo
{
public:
Foo(){}
~Foo()
{
Singleton::Instance().DoStuff();
}
};
int main()
{
static Foo foo;
return 0; // Undefined behavior after this line, when program
cleanup occurs!
}
static de-initialization fiasco.
Sorry for dropping in, maybe I have not the right grip on the subject
but I want to show what I understand about your program, and take the
chance to learn something new.
If I get it right, this is the sequence:
--- start of execution
- m_instance gets created
- foo gets created
The order of initialization is not defined. foo might get created
before m_instance or vica versa.
- main returns
Yes
- foo starts being destroyed
- a Singleton gets created
Maybe, maybe not. The order of deinitialization is also undefined.
- x gets created
- x gets destroyed
This will happen only when foo gets destroyed, when that happens isn't
defined
- foo finishes its destruction
yes
- m_instance gets destroyed
Whether or not this occurs before foo is destroyed is undefined. That
is the problem and is the de-initialization fiasco.
--- end of execution
Have I got it right? How that relates to the de-initialization fiasco?
Don't take me wrong, those are sincere questions.
-
The problem is there are two variables in static or global space. The
destruction of one relies on the other existing. Since, the order of
de-initialization is undefined, one cannot guarentee the other exists
at that point. This occurs after the return 0; statement in main,
which makes it a hell of a thing to debug if you don't know what the
problem is already. Especially, in a more complicated scenario where
the return of GetInstance might be used indirectly (such as someone
storing it or deep in a call stack)
The way to avoid this is to make sure that no global or static depends
on another in its destruction, which I argue is fine and dandy on a
small project or one that you write completely alone, but I have found
in practice (5 out of 6 jobs) that it will indeed cause a problem at
some point.
The worst of it is you will have to convince all your peers it is a
problem! Sometimes the program will execute and exit without any
indication of a problem. Then one day someone adds a line somewhere
completely unrelated, and blamo, it doesn't run anymore. It can also
run on one persons machine while not running on another's! Mix that
with working with people who have 30+ years on you and have no respect
for your "c++ ways" and you will have one ton of work frustration.
It is much easier for everyone to simply pass a reference to the would
be singleton around. After all how much of a difference is there in a
caveat that says" There should only be one instance of this object"
and a caveat that says "We must check all dependencies on this
singleton at all times as it relates to initializiation and de-
initialization". I beleive the former is simpler to understand and
enforce for all parties involved. 80% of your peers might not even
know what a singleton is much less what the de-initialization fiasco
is. Hopefully, they all understand what a reference is and how to use
it.