Hi Christian,
In your singleton example, there is no partical different between:
class Singleton
{
public:
Singleton& Instance() {
...
return *fgInstance;
}
private:
static Singleton* fgInstance; // Only a _declaration_!
...
};
and
class Singleton
{
public:
Singleton& Instance() {
static Singleton* fgInstance; // Only a _declaration_!
...
return *fgInstance;
}
private:
...
};
is there? (In both case fgInstance is only used via the Instance method!
> Could you explain why you believe a static function variable
> is better style than a class variable?
There is 2 reason
The order of initialization matters during the load shared time of the shared library.
The compiler/linker are free to 'run' the initialization the global
variables at any time
during the loading of the library.
On the other hand, a static function member must be initialization at the
time the function
is being entered.
Of course, this does not matter of your fgInstance since it is a pointer and
the pointer
default to 0. However it does matter for your fgLock Mutex.
For example if somebody define (at global scope)
// File user.cxx
int myvalue = Singleton::Instance()->GetValue();
While loading user.o, the linker compiler must initialize 'myvalue'. However, if you singleton.cxx is part of the same library, it can 'run' this initialization __before__ or __after__ it run the constructor for Mutex; i.e. running the initialization for
Mutex Singleton::fgLock;
So when executing Instance in part the line:
LockGuard g(fgLock);
You have _NO_ guarantee that fgLock is a valid initialized object ...
Cheers,
Philippe.
-----Original Message-----
From: Christian Holm Christensen [mailto:cholm_at_nbi.dk]
Sent: Thursday, May 29, 2008 9:33 AM
To: Philippe Canal
Cc: 'Tom Roberts'; 'ROOT Talk'
Subject: RE: [ROOT] Question about static class objects
Hi all.
On Tue, 2008-05-27 at 13:59 -0500, Philippe Canal wrote:
> Hi Tom,
>
> > Apparently I simplified it too much, and you took issue with C++ style
> > rather than the actual problem (though your workaround does work).
>
> Actually I did not take issue with C++ style [really :) I did not],
> I was merely mentioning thatthe only working work-around within CINT
> just happens to be better style :)
Uhm, in my mind, a static member of a class (or, as it's called in Java - a class variable) is far better style than a static variable in a function. Could you explain why you believe a static function variable is better style than a class variable?
Also, the use class variables is a very common idiom - especially for things like singletons:
struct Mutex
{
Mutex() { pthread_mutex_init(&fMutex); }
~Mutex() { pthread_mutex_destroy(&fMutex); }
void Lock() { pthread_mutex_lock(&fMutex); }
void Unlock() { pthread_mutex_unlock(&fMutex); }
private:
Mutex(const Mutex& mutex) {}
Mutex& operator=(const Mutex&) { return &this; }
pthread_mutex_t fMutex;
struct LockGuard
{
LockGuard(Mutex& m) : fMutex(m) { fMutex.Lock(); }
~LockGuard() { fMutex.Unlock(); }
private:
Mutex fMutex;
class Singleton
{
public:
Singleton& Instance() {
if (!fgInstance) {
LockGuard g(fgLock);
if (!fgInstance) // Prevent race-conditions
fgInstance = new Singleton;
}
return *fgInstance;
}
void DoSomething() {}
private:
Singleton() {}
Singleton(const Singleton&) {}
Singleton& operator=(const Singleton&) { return *this; }
Singleton* fgInstance; // Only a _declaration_!
Mutex fgLock; ?// Only a _declaration_!
};
// _Definition_ of class variables
Singleton* Singleton::fgInstance = 0;
Mutex Singleton::fgLock();
> (i.e. it is not important compared to the fact that one work and one does
> not)
...
> > Making list not be a class variable, but rather a local static object in
> > an accessor function (as you suggest), complicates the code more than I
> > want to do (list is used several dozen times, and there are three such
> > TList-s).
>
...
> > Note that making try() not inline (separating its definition from the
> > class declaration) did not help.
"try" is a very bad name for an identifier since it's a keyword in C++. Why not call it "give_it_a_shot" instead?
> I
> PS.
> > The above code is straightforward, reasonable, and standard C++,
> > and it ought to work; I'm astounded this has not come up before --
> > this is a standard way to keep track of all instances of class Zap.
A better way, would probably be to have an external singleton object that you "register" objects of class Zap with - it separates the functionality of the Zap objects from the book-keeping of the objects.
> Well :), even in C++, this has many caveat, you have no control/guarantee
> of when the class static data member will be initialized and using this
> member during the shared library loading is __in C++__ undefined
> behavior.
Actually, you have perfect control of when a class variable is initialised - especially if you use the Singleton pattern. Since you must _define_ the class variable somewhere, you know exactly which value it has on start of execution/load/what not.
> And, yes, this does not apply to your specific case and CINT ought to
> function properly in this case; it does not and it is hard to fix :(
Replacing your stack object list with a heap object surprisingly works:
struct Zap
{
static TList* list;
};
TList* Zap::list = new TList();
void foo()
{
Zap::list->Clear();
}
which seems to indicate that CINTs problem is really that it doesn't understand the _definition_ of the heap variable.
Yours,
--
___ | Christian Holm Christensen
|_| | -------------------------------------------------------------
| | Address: Sankt Hansgade 23, 1. th. Phone: (+45) 35 35 96 91
_| DK-2200 Copenhagen N Cell: (+45) 24 61 85 91
_| Denmark Office: (+45) 353 25 447
____| Email: cholm_at_nbi.dk Web: www.nbi.dk/~cholm
| |
Received on Thu May 29 2008 - 16:45:45 CEST
This archive was generated by hypermail 2.2.0 : Thu May 29 2008 - 23:50:01 CEST