0

This post is what I just read.

The way he implements Singleton in C++ confuses me. I got several Questions about it and here is his code:

template<typename T>
class Singleton {
public:
    static T& getInstance() {  //Question 1
        return instance;
    }
private:
    static T instance;
};

class DebugLog : public Singleton<DebugLog> {  //Question 2
public:
    void doNothing() {}
};

Question

  1. I think we should put the static T& getInstance()'s definition outside of the class body, right?

  2. He tries to make class DebugLog a singleton class, but when he inherits Singleton<DebugLog>, the DebugLog doesn't already exist, right? If right, then how can the template class Singleton instantiate an un-existent class?

Community
  • 1
  • 1
Alcott
  • 17,905
  • 32
  • 116
  • 173
  • 4
    1 - you don't have to. 2 - [Curiously Recurring Template Pattern](http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern). – wkl Nov 21 '11 at 07:33

3 Answers3

5

1) Nope, it doesn't matter how you structure your code. Singleton isn't a class, by the way: It's a template. Since the full template definition must be visitible at any instantiation site anyway, you might as well define everything inline.

2) class DebugLog : public Singleton<DebugLog> is fine. We are not inheriting from a non-existing class; rather, we are inheriting from the class Singleton<DebugLog>. Templates can be instantiated on incomplete types. (There are several rules what you can and cannot do with such a type parameter.)

For example, template <typename T> class Foo { }; can certainly be instantiated on any type without problem. More interestingly, template <typename T> struct PointerFactory { typedef T * type; }; can be instantiated on any type, complete or not. In the present situation, the purpose of the template parameter in the CRTP is solely to inform the base class of its eventual derived type, so this is entirely fine.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • Does it mean, when a class is inheriting a template class, it doesn't matter what the template parameters are, right? – Alcott Nov 21 '11 at 07:44
  • @Alcott: This hasn't really anything to do with inheritance. The only question is whether you can instantiate the template or not. – Kerrek SB Nov 21 '11 at 07:59
1
  1. It would certainly be cleaner if the function were defined outside of the class, and make the code easier to read and to maintain. In this case, however, the complete class is small enough that the difference isn't very great, and of course, because we're dealing with a template, the actual definition still has to be included in every translation unit which uses it.

The C++ standard doesn't speak of “existence” with regards to classes (or anything else). At the point of template instantiation, name lookup finds DebugLog, and finds that it is a class (thus, a type). At that point, it is an incomplete type, and there are only limited things you can do with an incomplete type. If the class template which is instantiated doesn't do anything that requires a complete type (and Singleton doesn't), then there is no problem. (Note that only the class definition is instantiated at this point; class member functions will not be instantiated until they are used.)

I might add that there is still one important thing missing from the code you posted: there is no definition for the declaration Singleton::instance. You still need to add a:

template<typename T> T Singleton<T>::instance;

somewhere.

James Kanze
  • 150,581
  • 18
  • 184
  • 329
  • yes, that's missing. Furthermore, in order to make the Singleton a real Singleton, I think we should make Singleton's ctor `Singleton()` a protected/private member function, right? – Alcott Nov 21 '11 at 10:03
  • @Alcott Since `Singleton` is designed to be derived from, making its constructor `protected` would seem to be a good move. One thing `Singleton` can't do, and that needs doing, is to ensure that `DebugLog` has a private constructor, and that `Singleton` is a friend, in order to use it. – James Kanze Nov 21 '11 at 10:26
  • that's right,:). Another thing is, when will the member function be instantiated in a template class? – Alcott Nov 21 '11 at 10:32
  • @Alcott When it's "used". For the standard's definition of "used"; a virtual function is considered "used" if any instance of an object of that type is constructed (because its address must be put in the `vtable`). Otherwise, the function will only be instantiated if you actually call it, and the instantiation context will be that of where the function is called. Similarly, a static member will only be instantiated if it is used; in this case, if (and when) you call `instance`. – James Kanze Nov 21 '11 at 13:59
-3

You must use a pointer to T in this case:

template<typename T>
class Singleton {
public:
    static T& getInstance() {
        static T * instance = NULL;
        if (!instance)
            instance = new T;
        return *instance;
    }
};

class DebugLog : public Singleton<DebugLog> {  //Question 2
    public:
        void doNothing() {}
};
Tio Pepe
  • 3,071
  • 1
  • 17
  • 22
  • -1 Not only you do not "must" use static pointer instance you also do not destroy the object in your code. – Artyom Nov 21 '11 at 07:49