468,512 Members | 1,426 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 468,512 developers. It's quick & easy.

std::atexit

I am attempting to write a "Phoenix Singleton" using the book "Modern C++
Design" by Alexandrescu
I do not understand his use of...

#ifndef ATEXIT_FIXED
std::atexit(Kill);
#endif

....in the source below. I understand the problem, but not how a preprocessor
directive will fix it. He says the standard is unclear about the situation
where one call to register with std::atexit is the result of is made as an
effect of another std::atexit registration. Can anyone be more specific on
how to fix the problem?

Source (forgive the indenting problems as a result of editor
incompatibilities):
// .h file
#ifndef SINGLETON_PHOENIX
#define SINGLETON_PHOENIX
#include "BaseException.h"
namespace cpisz_common_lib
{
//----------------------------------------------------------------------------------------------------------------------
/**
* Singleton_Pheonix
*
* A singleton pattern that guarentees an instance will always be available.
*
*/
class Singleton_Phoenix
{
public:
/**
* Retreives a reference to this singleton
*/
static Singleton_Phoenix & GetInstance();
private:
static void Create();
static void Kill();
static void OnDeadReference();
Singleton_Phoenix();
Singleton_Phoenix(const Singleton_Phoenix &);
virtual ~Singleton_Phoenix();
Singleton_Phoenix & operator = (const Singleton_Phoenix &);
static Singleton_Phoenix * m_instance; // Pointer to the instance of this
object
static bool m_destroyed; // Flag that indicates the instance has been
destroyed
};
} // namespace cpisz_common_lib
#endif

// .cpp file
#include "Singleton_Phoenix.h"
#include <cstdlib>
namespace cpisz_common_lib
{
//----------------------------------------------------------------------------------------------------------------------
Singleton_Phoenix * Singleton_Phoenix::m_instance = 0;
bool Singleton_Phoenix::m_destroyed = false;
//----------------------------------------------------------------------------------------------------------------------
Singleton_Phoenix & Singleton_Phoenix::GetInstance()
{
// Check if the object is instantiated
if( !m_instance )
{
// Check for dead reference
if( m_destroyed )
{
// Create a new instance, replacing the old destroyed instance
OnDeadReference();
}
else
{
// Create the first instance
Create();
}
}
return *m_instance;
}
//----------------------------------------------------------------------------------------------------------------------
void Singleton_Phoenix::Create()
{
static Singleton_Phoenix instance;
m_instance = &instance;
}
//----------------------------------------------------------------------------------------------------------------------
void Singleton_Phoenix::Kill()
{
// Set the instance pointer to NULL and destroyed flag to true;
m_instance->~Singleton_Phoenix();
}
//----------------------------------------------------------------------------------------------------------------------
void Singleton_Phoenix::OnDeadReference()
{
// Get the shell of the old reference to the instance
Create();
// Create a new instance at that same address
// Using the "placement new operator"
new(m_instance) Singleton_Phoenix;
// Queue this new objects destruction
#ifndef ATEXIT_FIXED
std::atexit(Kill);
#endif
// Reset the destoryed flag
m_destroyed = false;
}
//----------------------------------------------------------------------------------------------------------------------
Singleton_Phoenix::~Singleton_Phoenix()
{
m_instance = 0;
m_destroyed = true;
}
} // namespace cpisz_common_lib
Jan 2 '08 #1
2 4143
On Jan 2, 6:19 am, "Christopher Pisz" <some...@somewhere.netwrote:
I am attempting to write a "Phoenix Singleton" using the book
"Modern C++ Design" by Alexandrescu I do not understand his
use of...
#ifndef ATEXIT_FIXED
std::atexit(Kill);
#endif
...in the source below. I understand the problem, but not how
a preprocessor directive will fix it. He says the standard is
unclear about the situation where one call to register with
std::atexit is the result of is made as an effect of another
std::atexit registration.
C99 is not unclear about this (although I seem to remember it
being undefined behavior in C90, and thus in C++98).
Can anyone be more specific on how to fix the problem?
Which problem? The code you posted has several different cases
of undefined behavior. All the #ifndef does is cause atexit not
to be called if ATEXIT_FIXED is defined.

I've not studied it in detail, but even after a quick glance, it
is apparent that if Kill() is ever called (and it will be called
if atexit is called), the destructor is called twice for the
same object. This is undefined behavior, and in a non-trivial
class, will almost certainly get you into trouble. So you
almost certainly have to defined ATEXIT_FIXED for the code to
work.

The obvious way to achieve the supposed goal (that an instance
will always be available) is to create the instance with new,
and never destruct it.

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Jan 2 '08 #2
On Jan 2, 6:02 am, James Kanze <james.ka...@gmail.comwrote:
On Jan 2, 6:19 am, "Christopher Pisz" <some...@somewhere.netwrote:
[snip]
He says the standard is
unclear about the situation where one call to register with
std::atexit is the result of is made as an effect of another
std::atexit registration.

C99 is not unclear about this (although I seem to remember it
being undefined behavior in C90, and thus in C++98).
What does C99 say about it?
Can anyone be more specific on how to fix the problem?

Which problem? The code you posted has several different cases
of undefined behavior. All the #ifndef does is cause atexit not
to be called if ATEXIT_FIXED is defined.
That is what I suspected. If that is the case I don't see any reason
to put the preprocessor directive in there at all. I should always
execute that block.

I've not studied it in detail, but even after a quick glance, it
is apparent that if Kill() is ever called (and it will be called
if atexit is called), the destructor is called twice for the
same object. This is undefined behavior, and in a non-trivial
class, will almost certainly get you into trouble. So you
almost certainly have to defined ATEXIT_FIXED for the code to
work.
So, the code will not have undefined behavior if I remove the
preprocessor directive in that case? I do not see the other cases you
speak of even after examining the code in detail. The only problem I
can forsee is what happens at application exit when a registration
using std::atexit() is made as a result of another registration using
atexit(), which is the behavior my post is asking about. Anyone see
other cases of undefined behavior? Anyone have a definition of the
behavior mentioned?

The obvious way to achieve the supposed goal (that an instance
will always be available) is to create the instance with new,
and never destruct it.
I am unclear about this suggestion. If I new something and do not
delete it, is that not a memory and possibly a resource leak? What
will happen in the case that one of these singletons is dependent on
another at the time of application exit?

I am getting the feeling that what you are telling me is that this
book is out of date and there may be a better solution available. If
so, does anyone have a link? I have googled and found several
singleton implementations, but none of which seem to address the flaws
that this one is attempting to address.

I really want to try to avoid the authors proposal of implementing a
"dependency manager" and global "setlongevity(int)" methods. It seems
overly complex to me.
Jan 2 '08 #3

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

13 posts views Thread by Siemel Naran | last post: by
8 posts views Thread by JKop | last post: by
5 posts views Thread by John Ratliff | last post: by
12 posts views Thread by keepyourstupidspam | last post: by
reply views Thread by Andreas Schmitt | last post: by
reply views Thread by NPC403 | last post: by
1 post views Thread by fmendoza | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.