1

I was looking into Alexandrescu's singleton created with policies, which is an interesting design. (http://loki-lib.sourceforge.net/html/a00670.html)

However, he first explains that you should guarantee a Singleton's uniqueness, which I agree with. But when you look at the policy implementation, he has a policy CreateWithNew which invokes the new operator on the argument provided with T. which means the constructor has to be public, meaning any user creating the singletonHolder can also instantiate that class directly himself.

Obviously it is still a nice design, but I just wanted to make sure if I missed something important or if he sacrificed the uniqueness for a versatile design.

Thanks!

A test example: The following class has a TestObject which is the Singleton class, and a simple createViaNewPolicy which just uses new to allocate the singleton. notice that the constructor of TestObject has to be public in order for this to work.

//////////////////////////////////////////////////////////////////////////
class TestObject
{
public: // change this to private (to guarantee uniqueness) but then it wont compile
    TestObject() {}
    int foo() {return 1;}
    ~TestObject() {}
};

//////////////////////////////////////////////////////////////////////////
template< class T, template <class> class CreationPolicy >
class SingletonHolder
{
public: 
    T* SingletonHolder<T, CreationPolicy>::Instance()
    {
        if (!pInstance_)
        {
            pInstance_ = CreationPolicy<T>::Create();
        }

        return pInstance_;
    }
private:
    static T* pInstance_;
};

template< class T, template <class> class CreationPolicy >
T* SingletonHolder<T, CreationPolicy>::pInstance_;

//////////////////////////////////////////////////////////////////////////
template<class T>
class CreateViaNew
{
public:
    static T* Create()
    {
        return new T();
    };
};

//////////////////////////////////////////////////////////////////////////
int _tmain(int argc, _TCHAR* argv[])
{
    SingletonHolder<TestObject, CreateViaNew> mySingletonHolder;
    TestObject* testObj = mySingletonHolder.Instance();
    return 0;
}
Giel
  • 397
  • 1
  • 9

1 Answers1

0

CreateUsingNew is just the policy. They way it's used is as a template template parameter inside the Singleton class. So the singleton class will have the following layout (exctract from modern C++ design) :

class Singleton
{
    Singleton& Instance();
    ... operations...
public:
    Singleton();
    Singleton(Singleton const&);
    Singleton& operator=(Singleton const&);
    ~Singleton();
}

There the creation of the object can only be done through the Instance method. In turn that method reads (extract from the link to Loki) :

 template
 <
     class T,
     template <class> class CreationPolicy,
     ... some other arguments... 
 >
 void SingletonHolder<T, CreationPolicy, 
     ...some other arguments...>::MakeInstance()
 {
    ... stuff ... 
     if (!pInstance_)
     {
         if (destroyed_)
         { /* more stuff */ }
         pInstance_ = CreationPolicy<T>::Create();
         /* even more stuff */
     }
 }

So the line where the magic happens is pInstance = CreationPolicy<T>::Create();

Itself, every construction method for a Singleton object is private and underlying implementation of the construction policy can only be accessed through the public MakeInstance method

Nikos Athanasiou
  • 29,616
  • 15
  • 87
  • 153
  • Again here.. the CreationPolicy has a function Create, which you call to populate the private instance that you return in the Instance() function. but in order for Create to create a new object it has to call the new operator and the constructor.. which will be public, right? – Giel May 29 '14 at 16:52
  • @Giel No, you're reading this the wrong way. The `CreationPolicy` calls the constructor of `T`, not the constructor of `Singleton`. In turn the signleton holds a pointer to `T` but the constructor of `Singleton` itself is private. So accessing `T`s through the Singleton will give you a unique instance – Nikos Athanasiou May 29 '14 at 23:14
  • I have updated the question with a simple sample, please try it and let me know where I took a wrong turn :) just compile/run it and change the TestObject's constructor to private to hide it (as a good singleton should) and try again – Giel May 30 '14 at 16:45
  • @Giel The wrong turn is at the usage of singleton. You see, you're supposed to acquire unique instances of `T` through the `Singleton`. Now `T` is supposed to be constructible (not hide its constructor) but `Singleton` is the one whose constructor you can't call directly. To sum up your singleton class (that will give you a unique `TestObject*`) is `Singleton` not `TestObject`. There are other implementations of singleton, where you have your class **inherit** from a `Singleton` class, thus embedding uniqueness in the class's interface but that's not the case here. – Nikos Athanasiou May 30 '14 at 16:52
  • @Giel I'm supposing you have the book; if that's the case you can check ch.6.11 "Working with SingletonHolder". A small extract says _The SingletonHolder class template does not provide application-specific functionallity. It merely provides Singleton-specific services over another class - T in the code in tnis chapter. We call T the client class_ . In your case `TestObject` is the client class. – Nikos Athanasiou May 30 '14 at 17:15
  • Thanks, that makes sense. the only thing left than is: you would agree that this leaves room for abuse? since people could instantiate TestObject by themselves and use it as a normal manager. whereas the classic singleton would completely block any of this – Giel May 30 '14 at 17:22
  • @Giel Even more, one could argue, that everything is hackable. You would have to restrain yourself in the ways you access the client instances. – Nikos Athanasiou May 30 '14 at 17:51
  • I will accept this one as the discussion will suffice for an answer for people in the future :) Thanks for the input Nikos – Giel May 30 '14 at 22:13