Singletons using smart pointers

Hey there,
so I've been fiddling with singletons lately and tried to write one using smart pointers so I don't have to worry about them leaking.
I've seen some people simply use a static shared_ptr but I don't see how that's any better than using a static class variable (which is not good!). Also, you would achieve the same effect using a static scoped_ptr (which is still bad!).

So this is what I came up with:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// ---------------------------------------------------
// singleton.h:
#ifndef SINGLETON_H_
#define SINGLETON_H_

#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>

class Singleton : boost::noncopyable {
 public:
  static std::shared_ptr<Singleton> Get();
  ~Singleton() {singleton_ = NULL;}

 private:
  Singleton() {};

  static Singleton* singleton_;
};

#endif

// ---------------------------------------------------
// singleton.cc:
#include "singleton.h"

std::shared_ptr<Singleton> Singleton::Get() {
  if (!singleton_) {
    singleton_ = new Singleton();
  }
  return std::shared_ptr<Singleton>(singleton_);
}

Singleton* Singleton::singleton_ = NULL;

It solves the issue of the shared_ptr being static by only creating shared_ptrs when a reference to the object is requested. It also gives the possibility of creating another singleton after the first one has been destroyed, so eventually you can create as many singletons as you want but only have one at a time.

So what do you guys think? Will this work?
Why not just use the simpler and more traditional approach:

1
2
3
4
5
6
7
8
9
10
11
12
class Singleton
{
private:
  Singleton() { };

public:
  Singleton& Get()
  {
    static Singleton the_singleton;
    return the_singleton;
  }
};
Last edited on
@Disch: +1

Also: http://www.boostcookbook.com/Recipe:/1235044

That should go into Boost if you ask me. The only worry is this: singleton's are evil.

http://blogs.msdn.com/b/scottdensmore/archive/2004/05/25/140827.aspx

Putting it in Boost would encourage people to abuse Singleton even more.
@Disch:
Simply because I don't like static class types. Their order of destruction and construction is not entirely specified in C++, so if you have multiple (different) singletons you can't be entirely sure which one is destroyed first, which is bad if one of the destructors uses the other singleton (e.g. for some logging stuff).
(... and also because I'm following the Google coding style ;))

@PanGalactic:
Dunno, I like singletons for some things.
Logging for example. You only have one console to print your stuff to, so why the need for more?
Also something I'm currently working on: SDL. You can only have one active screen at a time and only one instance of SDL running at a time (between SDL_Init() and SDL_Quit()). So why the need for more than one of these?
Singletons are not all that evil ;).
Last edited on
First, I could never understand singletons. Do they disallow multiple ownership or multiple instantiation? And if the singleton objects can be owned by more than one client, are they required to be stateless (from the perspective of those clients)?

Regarding your code. If you provide two shared_ptr's to the same object and one of them releases the object, wouldn't the second one be left dangling?

EDIT: Redirected the question to separate thread here: http://www.cplusplus.com/forum/general/37129/

Regards
Last edited on
Their order of destruction and construction is not entirely specified in C++, so if you have multiple (different) singletons you can't be entirely sure which one is destroyed first, which is bad if one of the destructors uses the other singleton (e.g. for some logging stuff).


When declared locally, they're constructed on first use, so construction order isn't a problem.

However destruction order is a valid point. However I fail to see how using a smart pointer solves that problem.
Opossum's singleton never destroys the object. Both the thread-safe Boost singleton and Disch's singleton use static objects which guarantee destruction via static destructors. A "new" without a "delete" just leaks resources.
May be I don't understand this right. Can I do this:
1
2
3
4
5
std::shared_ptr<Singleton> ptr1 = Singleton::Get();
{
    std::shared_ptr<Singleton> ptr2 = Singleton::Get();
}
//what happens to ptr1 here 
Oh, duh. Same here:

1
2
3
4
5
6
7
{
    std::shared_ptr<Singleton> ptr = Singleton::Get();
}
{
    // refers to destroyed pointer.
    std::shared_ptr<Singleton> ptr = Singleton::Get();
}


Nah, there is code in the destructor that protects from this:
1
2
3
4
5
6
7
{
    std::shared_ptr<Singleton> ptr = Singleton::Get();
}//~Singleton() {singleton_ = NULL;}
{
    //if (!singleton_) {...
    std::shared_ptr<Singleton> ptr = Singleton::Get();
}
Last edited on

The only worry is this: singleton's are evil.


Singletons are only evil because there is no way they can be 100% correctly implemented. The Disch's solution is almost perfect, except for two things:
1. the destruction order is unknown
2. you can end up having more singletons in multithreaded environment (well, the probablity for that is 1/10000000000 or less, but, you know, 1/10000000000 happens so often "the next Friday")

IMHO if the singleton pattern was a part of the language, not a library hack, all problems would be gone.



Last edited on
Regarding your code. If you provide two shared_ptr's to the same object and one of them releases the object, wouldn't the second one be left dangling?

That's a solid concern, I didn't notice that. So I basically had to make the destructor private and befriend the destructing part of shared_ptr. This is getting ugly though :/.

Opossum's singleton never destroys the object.

Actually it should. Whenever Get() is called, a shared_ptr is passed to the calling scope. When the last one of these shared_ptrs is destroyed, they will delete the singleton. That's why I used shared_ptrs, so I don't have to delete them manually.

May be I don't understand this right. Can I do this:

A shared_ptr only destroys the object when there are no other shared_ptrs pointing to that same object (afaik?). So the inner pointer running out of scope would simply do nothing but free the pointer memory.
Again, if there are two clients of the singleton, the second client will peruse the object instantiated for the first client. Say this is a stream. The first client uses the stream erroneously. Then, this affects the second client, which had nothing to do with the error.m That's why I wonder if ownership should be restricted.

Should all acquired instances behave with all clients independently? Should they behave as if they were acquired in freshly constructed state, or are they permitted to start with observable arbitrary state? What are the formal requirements that make some class or resource singleton? I know they are generally used for externally supplied resources that permit only one access point, for lazy initialization, and for pooling-like optimization. But what are the specifications that bind the producer regarding the state of the singleton object upon receipt, and what are the requirements regarding the independence of the interactions of several clients with a single object?

Regards
@Opposum
Shared ptrs only track the number of references to a given object through assignment and copy construction of shared ptrs. That is, having two shared ptrs to the same object does not guarantee that they will be aware of each other, unless one of those shared pointers is produced by a series of assignment and copy constructions from the other. In fact, the two shared pointers must have the same reference counter for this to work. And when you construct shared pointer using raw pointer, a brand new reference counter is created every time.

Regards
Again, if there are two clients of the singleton, the second client will peruse the object instantiated for the first client. Say this is a stream. The first client uses the stream erroneously. Then, this affects the second client, which had nothing to do with the error.m That's why I wonder if ownership should be restricted.

I don't think the singleton pattern specifies that. All I can find for definition is basically "one object only" and "they are overused" :). I'd think it largely depends on your individual needs. Guess that's also why there's no built-in singleton template yet. That and because of the undefined behavior.

Shared ptrs only track the number of references to a given object through assignment and copy construction of shared ptrs. That is, having two shared ptrs to the same object does not guarantee that they will be aware of each other, unless one of those shared pointers is produced by a series of assignment and copy constructions from the other. In fact, the two shared pointers must have the same reference counter for this to work. And when you construct shared pointer using raw pointer, a brand new reference counter is created every time.

Oh my. That won't work at all then. Is there a possibility to "link" two shared_ptrs without to much hassle?

I'll better just stick to static objects. This is getting quite a bit over-sophisticated for my needs.
Is there a possibility to "link" two shared_ptrs without to much hassle?
Even if there was (and I don't think there is), it would have been something computationally expensive. The raw pointer contains no information who connects to it. We wouldn't need smart pointers if it did :) So, the only way to associate raw pointers to existing reference counters is to keep track of the current reference counters in some map (pretty much like string interning, if you google it). I don't think even the boost guys go that far.

On a side note, I used to hate the idea of garbage collection (I mean the other kind). But now I see it has some distinctive advantages, because the reference count is deduced when collection is performed. And you don't have problem with circular references. And you can point to sub-objects of composite objects without worrying that the latter will be released. The delayed finalization bugs me. Also, it can be problem for real-time, but if you have leaks, that can be a problem too. I like the approach I found here (http://acdk.sourceforge.net/acdk/docs/hb/lang/acdk_hb_memmgmt_rcgc_mechanism.html), which is to use reference counting and garbage collection on top of that. Most objects are released as early as possible, and only the few that remain are garbage collected. The objects are overall destroyed sooner, and the gc is left with less work.

What I mean is, there is interesting algorithmic layer behind all this. I used to believe that all this memory management stuff (even refcnt at one point) is all propaganda, but now I see that I was keeping my eyes wide shut.

Regards
It just occurred to me that you can cache weak pointer inside the singleton and then use it to produce the shared pointers. I will try to implement this later, but I've got to run now.

The delayed finalization bugs me.


The delayed finalization is a theoretical problem, not a practical one. In rare cases, when it is needed, you can force releasing of resources manually. However, in the 99% cases where you don't need deterministic destruction, you can rely on GC.
Last edited on
This, I think (tested it a bit) works:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>

class Singleton : boost::noncopyable {
public:
  static boost::shared_ptr<Singleton> Get();
  ~Singleton() {/*weak ptr does not have to be nulled*/}

private:
  Singleton() { };

  static boost::weak_ptr<Singleton> singleton_;
};

boost::shared_ptr<Singleton> Singleton::Get() {
  boost::shared_ptr<Singleton> instance = singleton_.lock();
  if (!instance) {
    instance.reset(new Singleton());
    singleton_ = instance;
  }
  return instance;
}


rapidcoder wrote:
In rare cases, when it is needed, you can force releasing of resources manually.
Indeed it is not mainstream concern. But the client of my class has to know I require special lifetime management in order to force my finalization. I know it is not problem when development is virtually gray-box. But for me, the whole point of automatic management, besides suppressing inadvertent leaks, is to abstract from the lifetime management aspect (which may change with the implementation of my object). Also, if the lifetime of such object is not associated with certain stack frame, you need reference counting again. And the problems arise again, because this will not be supported transparently under the hood. For example, the issue with opossum's singleton can show up. If the objects were ref counted and gc-ed by the VM the performance would arguably drop, but the abstraction would be full.

The RAII crowd says something similar about circular references. They say you can avoid them with weak pointers or you can use management objects. But the entire exercise is not to track down which object is referenced by who and in what way. (I don't mean complete code ignorance, but just separating the memory management aspect.) If I have to do such analysis, then I am using smart pointers only to deal with exception handling.

I agree that the finalization issue is theoretical. But then, implementation abstraction is also theoretical issue. Does this mean that they don't have practical implications? I hope I don't sound worked up or smth.

Regards
Topic archived. No new replies allowed.