By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
454,344 Members | 1,965 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 454,344 IT Pros & Developers. It's quick & easy.

Globals initialization using templates

P: n/a

The subject is a bit misleading because I really can't figure out what
the following code snippet is doing and would appreciate any help in
deciphering it.

I mean I can understand code-wise what is going on but I am missing the
larger picture.

In what circumstances would I use this?

template<typename T>
class Globals
{
public:
Globals()
{
if (impl == NULL)
{
init();
}
}
T* operator->() const
{
return impl;
}
private:
static T* impl;
static void init()
{
static union
{
char buf[ sizeof( T ) ] ;
double dummyForAlignment ;
} data ;
impl = new (data.buf) T;
}
};

template<typename T>
T* Globals<T>::impl = NULL;

Nov 16 '06 #1
Share this Question
Share on Google+
15 Replies


P: n/a

Dilip wrote:
The subject is a bit misleading because I really can't figure out what
the following code snippet is doing and would appreciate any help in
deciphering it.

I mean I can understand code-wise what is going on but I am missing the
larger picture.

In what circumstances would I use this?

template<typename T>
class Globals
{
public:
Globals()
{
if (impl == NULL)
{
init();
}
}
T* operator->() const
{
return impl;
}
private:
static T* impl;
static void init()
{
static union
{
char buf[ sizeof( T ) ] ;
double dummyForAlignment ;
} data ;
impl = new (data.buf) T;
}
};

template<typename T>
T* Globals<T>::impl = NULL;
Defining Globals in a multithreaded environment (even though toe code
here doesnt have any multi threading constructs)where you could control
the order of Initialization especially when you oculd be possibly
having a bunch of globals depending upon each other.

Nov 16 '06 #2

P: n/a
ampar...@gmail.com wrote:
Defining Globals in a multithreaded environment (even though toe code
here doesnt have any multi threading constructs)where you could control
the order of Initialization especially when you oculd be possibly
having a bunch of globals depending upon each other.
can you give me a short example?

I thought the order of initialization for global variables are defined
within a translation unit?
Do you mean cases where global vars defined across translation units
somehow end up depending on one another for initialization? If so, how
does that class solve the problem?

Nov 16 '06 #3

P: n/a
Dilip wrote:
The subject is a bit misleading because I really can't figure out what
the following code snippet is doing and would appreciate any help in
deciphering it.

I mean I can understand code-wise what is going on but I am missing the
larger picture.

In what circumstances would I use this?

template<typename T>
class Globals
{
public:
Globals()
{
if (impl == NULL)
{
init();
}
}
T* operator->() const
{
return impl;
}
// missing destructor
// this is necessary in case T manages some kind of resource.
~Globals()
{
impl->T::~T();
}
private:
static T* impl;
static void init()
{
static union
{
char buf[ sizeof( T ) ] ;
double dummyForAlignment ;
} data ;
impl = new (data.buf) T;
}
};

template<typename T>
T* Globals<T>::impl = NULL;
Nov 16 '06 #4

P: n/a

Dilip wrote:
ampar...@gmail.com wrote:
Defining Globals in a multithreaded environment (even though toe code
here doesnt have any multi threading constructs)where you could control
the order of Initialization especially when you oculd be possibly
having a bunch of globals depending upon each other.

can you give me a short example?

I thought the order of initialization for global variables are defined
within a translation unit?
Do you mean cases where global vars defined across translation units
somehow end up depending on one another for initialization? If so, how
does that class solve the problem?
what is the following code doing ?

static T* impl;
static void init()
{
static union
{
char buf[ sizeof( T ) ] ;
double dummyForAlignment ;
} data ;
impl = new (data.buf) T;
}

How many times do you think the Init function is called per type ?

Nov 16 '06 #5

P: n/a
red floyd wrote:
// missing destructor
// this is necessary in case T manages some kind of resource.
~Globals()
{
impl->T::~T();
}
That's not clearly the right thing. impl is a static and so it does not
necessarily need destruction from a memory leaking perspective.
Nov 16 '06 #6

P: n/a

Gianni Mariani wrote:
red floyd wrote:
// missing destructor
// this is necessary in case T manages some kind of resource.
~Globals()
{
impl->T::~T();
}

That's not clearly the right thing. impl is a static and so it does not
necessarily need destruction from a memory leaking perspective.
impl might be static....but it might be holding a pointer to an object
T which might be holding up stuff. Therefore you need to call the T's
destructor.

Nov 16 '06 #7

P: n/a
Dilip wrote:
The subject is a bit misleading because I really can't figure out what
the following code snippet is doing and would appreciate any help in
deciphering it.

I mean I can understand code-wise what is going on but I am missing the
larger picture.

In what circumstances would I use this?

template<typename T>
class Globals
{
public:
Globals()
{
if (impl == NULL)
{
init();
}
}
T* operator->() const
{
return impl;
}
private:
static T* impl;
static void init()
{
static union
{
char buf[ sizeof( T ) ] ;
double dummyForAlignment ;
} data ;
impl = new (data.buf) T;
}
};

template<typename T>
T* Globals<T>::impl = NULL;
I don't see what some of the constructs are used - why not use this:

template<typename T>
class Globals
{
public:
T* operator->() const
{
static T * x = new T;
return x;
}
};

OK - so the memory for x is dynamically allocated in this example while
the OP example is not.

The use synax would be simply:

Globals<Type>()->Member ...
This below is probably equivalent to what was posted. (i.e. No dynamic
memory allocation.)

template<typename T>
class Globals
{
public:

T* operator->() const
{
static union
{
char buf[ sizeof( T ) ] ;
double dummyForAlignment ;
} data ;
static T * x = new (data.buf) T;
return x;
}
};

Nov 16 '06 #8

P: n/a
am******@gmail.com wrote:
Gianni Mariani wrote:
>red floyd wrote:
>>// missing destructor
// this is necessary in case T manages some kind of resource.
~Globals()
{
impl->T::~T();
}
That's not clearly the right thing. impl is a static and so it does not
necessarily need destruction from a memory leaking perspective.

impl might be static....but it might be holding a pointer to an object
T which might be holding up stuff. Therefore you need to call the T's
destructor.
That would mean that impl will point to unallocated memory if used like
this:
Globals<Type>()->X(); // ok works first time
Globals<Type>()->Y(); // oops - broken this time
Nov 16 '06 #9

P: n/a
Gianni Mariani wrote:
red floyd wrote:
>// missing destructor
// this is necessary in case T manages some kind of resource.
~Globals()
{
impl->T::~T();
}

That's not clearly the right thing. impl is a static and so it does not
necessarily need destruction from a memory leaking perspective.
Who said anything about memory? T could be a type that manages a
resource that could conceivably live beyond the lifetime of the program,
e.g. a SysV Semaphore.

When the program ends, Global<my_semaphore_manager_classshould bloody
well call the destructor for the my_semaphore_manager_class object it
created in impl, so that it can release the resource it holds.

Nov 16 '06 #10

P: n/a

Gianni Mariani wrote:
am******@gmail.com wrote:
Gianni Mariani wrote:
red floyd wrote:

// missing destructor
// this is necessary in case T manages some kind of resource.
~Globals()
{
impl->T::~T();
}
That's not clearly the right thing. impl is a static and so it does not
necessarily need destruction from a memory leaking perspective.
impl might be static....but it might be holding a pointer to an object
T which might be holding up stuff. Therefore you need to call the T's
destructor.

That would mean that impl will point to unallocated memory if used like
this:
Globals<Type>()->X(); // ok works first time
Globals<Type>()->Y(); // oops - broken this time
I dont understand this code above....
But you need some kind of descurtion on a refcount basis....

Nov 16 '06 #11

P: n/a
red floyd wrote:
Gianni Mariani wrote:
>red floyd wrote:
>>// missing destructor
// this is necessary in case T manages some kind of resource.
~Globals()
{
impl->T::~T();
}

That's not clearly the right thing. impl is a static and so it does
not necessarily need destruction from a memory leaking perspective.

Who said anything about memory? T could be a type that manages a
resource that could conceivably live beyond the lifetime of the program,
e.g. a SysV Semaphore.

When the program ends, Global<my_semaphore_manager_classshould bloody
well call the destructor for the my_semaphore_manager_class object it
created in impl, so that it can release the resource it holds.
We have no idea what this is used for. Clearly there is no destructor
and possibly for good reason. Saying it "should bloody well" have one
is making many assumptions that may not be valid.

Nov 17 '06 #12

P: n/a
Gianni Mariani wrote:
red floyd wrote:
>Gianni Mariani wrote:
>>red floyd wrote:

// missing destructor
// this is necessary in case T manages some kind of resource.
~Globals()
{
impl->T::~T();
}

That's not clearly the right thing. impl is a static and so it does
not necessarily need destruction from a memory leaking perspective.

Who said anything about memory? T could be a type that manages a
resource that could conceivably live beyond the lifetime of the
program, e.g. a SysV Semaphore.

When the program ends, Global<my_semaphore_manager_classshould
bloody well call the destructor for the my_semaphore_manager_class
object it created in impl, so that it can release the resource it holds.

We have no idea what this is used for. Clearly there is no destructor
and possibly for good reason. Saying it "should bloody well" have one
is making many assumptions that may not be valid.
Exactly. We have no idea what this is used for. Therefore is should
behave properly in the case where the template parameter has a
non-trivial destructor.
Nov 17 '06 #13

P: n/a
red floyd wrote:
....
Exactly. We have no idea what this is used for. Therefore is should
behave properly in the case where the template parameter has a
non-trivial destructor.
Can you make a logical argument why is "requires" a destructor making no
assumptions ?
Nov 17 '06 #14

P: n/a
Gianni Mariani wrote:
red floyd wrote:
...
>Exactly. We have no idea what this is used for. Therefore is should
behave properly in the case where the template parameter has a
non-trivial destructor.

Can you make a logical argument why is "requires" a destructor making no
assumptions ?
Because if T has a trivial destructor, then no harm is done by invoking
its destructor. If T has a non-trivial destructor, then failure to
invoke it can cause problems. Therefore, the destructor should be invoked.
Nov 17 '06 #15

P: n/a
red floyd wrote:
....
>
Because if T has a trivial destructor, then no harm is done by invoking
its destructor.
I don't think "no harm" is entirely clear. I'm not suggesting this is
good code, but there have been badly designed systems where I have
needed to not call the destructor on system exit because bad things
would in fact happen. Hence, as a generalization, I don't think "no
harm" is supportable.
... If T has a non-trivial destructor, then failure to
invoke it can cause problems. Therefore, the destructor should be invoked.
Not all non-trivial destructors (for globals) need to be called. The
operating system does a much more efficient cleanup on exit than a

e.g. this code (brain dump - not checked)

#include <vector>
std::vector<int> * foo = new std::vector<int>(10000000);

int main()
{
}

will not delete the object pointed to by foo, however on all popular
operating systems (I don't talk about embedded ones), this code is well
behaved.

In general, you can't really bargain on global destructors being called
anyway because there are ways of termination that do not call the final
cleanup routines (memory fault, power failure, failure to catch
exception, memory depletion, unresovable page faults etc just to mention
some). So if your code truly depends on global destructors to be
called, you're in for trouble.

For example, if your code uses temporary files, you may want to "lock"
the file and on startup, cleanup all unlocked temporary files. You
could do the same for all persistent OS objects.

So the point is, your generalization is clearly incorrect. While it is
"preferable" to have destructors of global objects called, it is
certainly not required all the time and it certainly cannot be depended
on all the time.

All generalizations are wrong.

Nov 17 '06 #16

This discussion thread is closed

Replies have been disabled for this discussion.