473,387 Members | 1,542 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,387 software developers and data experts.

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 4736
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 thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

13
by: Siemel Naran | last post by:
Hi. I posted this question to comp.lang.c++, but am rephrasing it a bit from what I learned and posting to comp.lang.c++.moderated for more insight. So how do I solve my problem? I want it so...
8
by: JKop | last post by:
Let's say that when your program ends (no matter how) that you want a certain block of code to be executed at the end. Here's the code: std::cout << "The program will now end.\n";...
11
by: Jonan | last post by:
Hello, For several reasons I want to replace the built-in memory management with some custom built. The mem management itlsef is not subject to my question - it's ok to the point that I have...
5
by: John Ratliff | last post by:
For code that was part of the C library, being used in C++, should you always prefix std:: Specific examples: std::fopen std::fclose std::atexit Should I include
11
by: tomgee | last post by:
I saw it many times, // T.h: class T { public: static T* instance(); private: T() {}
12
by: keepyourstupidspam | last post by:
Hi, I am writing a windows service. The code runs fine when I start the service when my machine is running but it fails to start automatically when the machine reboots. The code bombs out when...
7
by: Adrian | last post by:
Hi, I have a large unmanaged static C++ library which I've wrapped using a small C++/CLR DLL. This is called from a C# client application. The static library has a singleton, however it appears...
0
by: Andreas Schmitt | last post by:
I am trying to get the PhoenixSingleton pattern example found in "Modern C++ Design" to run. I am using the Singleton in a DLL. I don't deliver any references of the Singleton to outside-DLL...
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.