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

C++ Singleton Pattern

P: n/a
Why aren't "Singletons" done like this in C++:

A.hpp:

class A
{
public: static A theA;

// ...

private:
A() { /* ... */ }
};

A.cpp:

A A::theA;

rather than the complicated approaches I've
seen with the instance being allocated with "new"?

Dec 13 '06 #1
Share this Question
Share on Google+
10 Replies


P: n/a
wk****@yahoo.com wrote:
Why aren't "Singletons" done like this in C++:

A.hpp:

class A
{
public: static A theA;

// ...

private:
A() { /* ... */ }
};

A.cpp:

A A::theA;

rather than the complicated approaches I've
seen with the instance being allocated with "new"?
Actually some of them are. Why do you say they aren't?

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Dec 13 '06 #2

P: n/a

wk****@yahoo.com wrote:
Why aren't "Singletons" done like this in C++:

A.hpp:

class A
{
public: static A theA;

// ...

private:
A() { /* ... */ }
};

A.cpp:

A A::theA;
Whats stopying me from copying an instance of A?

int main()
{
A b(A::theA);
}
>
rather than the complicated approaches I've
seen with the instance being allocated with "new"?
How about:

#include <iostream>
#include <ostream>

template< typename T >
T& instance() // by reference only
{
static T t;
return t;
}

class A {
friend A& instance< A >();
A() { std::cout << "A()\n"; }
A(const A& copy) { std::cout << "copy A\n"; }
public:
~A() { std::cout << "~A()\n"; }
};

int main()
{
A& r_a = instance< A >();
// A a = instance< A >(); // error
std::cout << "&r_a = " << &r_a << std::endl;
A& r_b = instance< A >();
std::cout << "&r_b = " << &r_b << std::endl;
}

/*
A()
&r_a = 0x501fe0
&r_b = 0x501fe0
~A()
*/

Dec 13 '06 #3

P: n/a
wk****@yahoo.com a écrit :
Why aren't "Singletons" done like this in C++:

A.hpp:

class A
{
public: static A theA;
private:
A() { /* ... */ }
};

A.cpp:

A A::theA;

rather than the complicated approaches I've
seen with the instance being allocated with "new"?
Your approach is dangerous, as you don't know when the object is
created. You are only able to successfully use it after you entered in
main(), and you should not use it after main() exit. It means that your
singleton cannot be used in static object construction and so on - note
that this might not be a problem in the end.

Meyer's singleton (the getInstance() function declares a static
variable and returns this variable) was probably what you got in mind -
the standard ensures that the static is constructed the first time you
entered in the function, so it is always valid - until you quit main()
(static objects order of destruction is well defined, but not easily
handled from the programmer point of view, so you'd better not use it
after you exit main()). Allocating the instance using new() in the
getInstance() function allows the same use as Meyer's singleton, but
the singleton is still valid until the memory is freed. If it is never
freed then you singleton is always valid.

* Your approach
class A
{
private:
static A theA;
A() { }
~A() { }
A(const A&) { }
A& operator=(const A&);
public:
// time of construction is not known by the programmer
// time of destruction is not known by the programmer
A& instance() { return theA; }
};

* Meyer's approach
class A
{
private:
A() { }
~A() { }
A(const A&) { }
A& operator=(const A&);
public:
// the instance will be created when you enter the
// function for the first time
// time of destruction is hard to tell from the programmer
// point of view
A& instance() { static A a; return a; }
};

* GoF approach:
class A
{
private:
A() { }
~A() { }
A(const A&) { }
A& operator=(const A&);
public:
// the instance will be created when you enter the
// function for the first time
// the instance is never destroyed
A& instance() { static A *a = NULL; if (!a) a = new A(); return a; }
};

There's a very interesting discussion about singleton and their
possible implementation in the Modern C++ book of Andrei Alexandrescu.

Regards,

-- Emmanuel Deloget, Artware

Dec 13 '06 #4

P: n/a
Salt_Peter wrote:
wk****@yahoo.com wrote:
Why aren't "Singletons" done like this in C++:

A.hpp:

class A
{
public: static A theA;

// ...

private:
A() { /* ... */ }
};

A.cpp:

A A::theA;

Whats stopying me from copying an instance of A?

int main()
{
A b(A::theA);
}
Yes, good point, I forgot the private undefined copy constructor.

rather than the complicated approaches I've
seen with the instance being allocated with "new"?

How about:

#include <iostream>
#include <ostream>

template< typename T >
T& instance() // by reference only
{
static T t;
return t;
}

class A {
friend A& instance< A >();
A() { std::cout << "A()\n"; }
A(const A& copy) { std::cout << "copy A\n"; }
public:
~A() { std::cout << "~A()\n"; }
};
So the reason for this is to avoid having, for classes with
all inline member functions (the exceptional case i would
think), a .cpp file that defines the single private instance?

Dec 13 '06 #5

P: n/a
Emmanuel Deloget wrote:
wk****@yahoo.com a écrit :
Why aren't "Singletons" done like this in C++:

A.hpp:

class A
{
public: static A theA;
private:
A() { /* ... */ }
};

A.cpp:

A A::theA;

rather than the complicated approaches I've
seen with the instance being allocated with "new"?

Your approach is dangerous, as you don't know when the object is
created. You are only able to successfully use it after you entered in
main(), and you should not use it after main() exit. It means that your
singleton cannot be used in static object construction and so on - note
that this might not be a problem in the end.

Meyer's singleton (the getInstance() function declares a static
variable and returns this variable) was probably what you got in mind -
the standard ensures that the static is constructed the first time you
entered in the function, so it is always valid - until you quit main()
(static objects order of destruction is well defined, but not easily
handled from the programmer point of view, so you'd better not use it
after you exit main()). Allocating the instance using new() in the
getInstance() function allows the same use as Meyer's singleton, but
the singleton is still valid until the memory is freed. If it is never
freed then you singleton is always valid.

* Your approach
class A
{
private:
static A theA;
A() { }
~A() { }
A(const A&) { }
A& operator=(const A&);
public:
// time of construction is not known by the programmer
// time of destruction is not known by the programmer
A& instance() { return theA; }
};

* Meyer's approach
class A
{
private:
A() { }
~A() { }
A(const A&) { }
A& operator=(const A&);
public:
// the instance will be created when you enter the
// function for the first time
// time of destruction is hard to tell from the programmer
// point of view
A& instance() { static A a; return a; }
};
My understanding is that the standard allows local statics to
be initialized any time before the line of executable code
following their definition is executed. So I don't see how
this addresses the order-of-intialization problem.
* GoF approach:
class A
{
private:
A() { }
~A() { }
A(const A&) { }
A& operator=(const A&);
public:
// the instance will be created when you enter the
// function for the first time
// the instance is never destroyed
A& instance() { static A *a = NULL; if (!a) a = new A(); return a; }
};
I dislike this because of the added overhead to every single access
to the instance.

(Insert by reference here any of the long heated threads about
whether minor optimizations are worth it.)

The are also cases where the fact that the instance is not
destroyed can be a problem. If the instance sets some
sort of lock flag in a file or in a shared memory segment,
the file will close/segment will detach on program exit,
but the lock flag won't be cleared.

Dec 13 '06 #6

P: n/a
wk****@yahoo.com wrote:
[..]
My understanding is that the standard allows local statics to
be initialized any time before the line of executable code
following their definition is executed. So I don't see how
this addresses the order-of-intialization problem.
Your understanding is incorrect. The local statics are initialised
when the control passes their initialisation for the first time.
[..]
V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Dec 13 '06 #7

P: n/a
Emmanuel Deloget wrote:
.....
// the instance will be created when you enter the
// function for the first time
// the instance is never destroyed
A& instance() { static A *a = NULL; if (!a) a = new A(); return a; }
// is this not the same ?
A& instance() { static A *a = new A(); return *a; }

With gcc, this is also thread-safe.
Dec 14 '06 #8

P: n/a
Victor Bazarov wrote:
wk****@yahoo.com wrote:
[..]
My understanding is that the standard allows local statics to
be initialized any time before the line of executable code
following their definition is executed. So I don't see how
this addresses the order-of-intialization problem.

Your understanding is incorrect. The local statics are initialised
when the control passes their initialisation for the first time.
....

Since you likely know the case-law on this much better than
me, I will take your word on this. Looking at Draft 98, 6.7-4
seems to unnecessary go around the block a few times.
Why not just say local statics are intialized when control
passes them, undefined value before initialization, and let
the as-if rule allow for optimized early initialization?

The implication of this is that the compiler has to generate
a hidden static flag to prevent re-initialization, and that flag
has to be checked every time control passes the local static
definition.

Dec 14 '06 #9

P: n/a
wk****@yahoo.com wrote:
....
The implication of this is that the compiler has to generate
a hidden static flag to prevent re-initialization, and that flag
has to be checked every time control passes the local static
definition.
Wait until you read about the order of destruction.
Dec 14 '06 #10

P: n/a
wk****@yahoo.com wrote:
Victor Bazarov wrote:
>wk****@yahoo.com wrote:
>>[..]
My understanding is that the standard allows local statics to
be initialized any time before the line of executable code
following their definition is executed. So I don't see how
this addresses the order-of-intialization problem.
Your understanding is incorrect. The local statics are initialised
when the control passes their initialisation for the first time.
...

Since you likely know the case-law on this much better than
me, I will take your word on this. Looking at Draft 98, 6.7-4
seems to unnecessary go around the block a few times.
Why not just say local statics are intialized when control
passes them, undefined value before initialization, and let
the as-if rule allow for optimized early initialization?

The implication of this is that the compiler has to generate
a hidden static flag to prevent re-initialization, and that flag
has to be checked every time control passes the local static
definition.
[Offtopic]
Standard only defines the behavior of local static variables. But how
it's achieved is highly implementation specific. In the real world,
local static variables are implemented like global static variables
(with/wo slight difference in the segments they initially occupy), they
have guaranteed memory storage by compiler. Linker looks them up and
generates relocatable code in the end.

Fei
Dec 15 '06 #11

This discussion thread is closed

Replies have been disabled for this discussion.