Thread: Help with a singleton class

  1. #16
    Registered User antred's Avatar
    Join Date
    Apr 2012
    Location
    Germany
    Posts
    257
    I've heard people argue vehemently for the usefulness of the singleton "pattern", but to be honest, I've never seen a scenario that wouldn't have worked just as well or better WITHOUT singletons. IMO usually it boils down to people being to friggin lazy to pass references to certain objects around, so instead they make them singletons so they can just access them from anywhere.

  2. #17
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    The real problem with singletons is the way in which they are implemented, IMO. Typically, raw memory allocation is used and a lack of error propagation when multiple objects are instantiated (the whole point of using a singleton in the first place!). Luckily, designing a generic singleton class that covers all of the important bases is fairly trivial:

    Code:
    template < typename Class >
    class singleton
    {    
    public:    
        singleton( void )
        {
            if( instance_ )
                throw *( Class* )this;
            instance_ = ( Class* )this;
        }
        virtual ~singleton( void )
        {
            instance_ = 0;
        }
        static Class& global( void )
        {
            return *instance_;
        }
    protected:
        singleton( singleton const& )
        {    }
        static Class*
            instance_;
    };
    template < typename Class >
    Class*
        singleton< Class >::instance_ = 0;
    Upon instantiation, the singleton "attaches" itself to the global instance, however it was allocated (ie: stack/heap); so long as no other object of that type is "alive" at that moment, no error occurs - otherwise, an exception is thrown. This affords one the flexibility to create scoped singletons on the stack, repeatedly from the heap, or even using a combination of the two! And note that when an exception IS thrown it's simply a reference to the offending instance, which can be caught as either a reference to Class OR a reference to a singleton<Class> (the latter syntax can be useful for clarity).

    Example usage would simply be:

    Code:
    class RadioStatistics : singleton<RadioStatistics>
    {
    private:
        map<string, int> m_songs;
        map<string, int> m_singers;
        RadioStatistics();
    public:
        string getMostPlayedSong();
        string getMostPlayedSinger();
    };
    Notice that I got rid of all of the other static members; trust me, they aren't necessary and only serve to muddle up your design. You can either access everything via RadioStatistics::global( ), directly from the object you instantiated, or from some "wrapper" object that essentially forwards all of the global() calls to itself.
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  3. #18
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    Typically, raw memory allocation is used and a lack of error propagation when multiple objects are instantiated.
    O_o

    The "Singleton" deciding where to live is appropriate. If the "Singleton" doesn't decide where to live, you get a broken "Singleton" if the first access to the "Singleton" class is inappropriate.

    There is no reason to propagate an error if you really want a "Singleton"; use techniques which completely forbid any attempt to create an instance of a "Singleton" object. (The "Singleton" can create a single instance basically fending for itself.) You simply don't need error propagation during program execution if misuse fails to compile.

    Luckily, designing a generic singleton class that covers all of the important bases is fairly trivial
    That example code is incomplete and/or wrong; you can't create any instances of `RadioStatistics' because the constructor is `private' but no instances are created on behalf of `singleton<?>'.

    That example code doesn't cover the major "use case" for "Singleton", global point of unique access; as you said, you can create a "scoped singletons on the stack" so code foreign to the first code called which creates a "scoped singletons on the stack" likely crashes because the copy constructor the exception mechanism calls gets an invalid instance of the object to copy. (You can't `throw' an object by reference. You can `throw' a pointer to an object which is just a value.)

    That example code doesn't solve the "Construction/Destruction Order Fiasco" so can't safely be used within `static' or `global' objects; you could create another layer, but you'd be using a "Singleton" class from within the mechanism solving the problem which is silly.

    That example code pretends to be a value class with normal semantics which is the worst possible thing for a "Singleton" class; the `singleton<?>' class should have a `protected' constructor and client classes should have a `private' constructor otherwise you don't actually have a "Singleton". (I maintain that not having a "Singleton" is a good idea.)

    Upon instantiation, the singleton "attaches" itself to the global instance, however it was allocated (ie: stack/heap); so long as no other object of that type is "alive" at that moment, no error occurs - otherwise, an exception is thrown.
    Your destructor for `singleton<?>' hasn't "unattached" itself so other objects being "alive" at the moment is the least of your worries; you never release ownership of the "Singleton" class contract so other code, or the same code executing at a different time, allocating (stack) a new instance of your completely fake "Singleton" raises an exception which calls a copy constructor on a DEAD object. (I apologize for the emphasis, but I wanted to be absolutely clear on the many problems with this example code.)

    This affords one the flexibility to create scoped singletons on the stack, repeatedly from the heap, or even using a combination of the two!
    If you are creating an object several times, you do not have a "Singleton" class (Again, I advise not having a "Singleton" class, but the point is, you would not have one if you wanted one.), and as before, using this class repeatedly over different points of allocation for the same client simply breaks.

    Yes, indeed, designing a generic "Singleton" class template that covers all the important bases safely is easy, but you haven't done it, nor have you, given your description, intended to create a "Singleton", and at the end of the day, most people shouldn't create a generic "Singleton" class templates; the existence of such a facility will increase the misuse of the already overused and misused "Singleton" pattern, and we don't want that.

    Soma

  4. #19
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    Quote Originally Posted by phantomotap View Post
    O_o

    The "Singleton" deciding where to live is appropriate. If the "Singleton" doesn't decide where to live, you get a broken "Singleton" if the first access to the "Singleton" class is inappropriate.

    There is no reason to propagate an error if you really want a "Singleton"; use techniques which completely forbid any attempt to create an instance of a "Singleton" object. (The "Singleton" can create a single instance basically fending for itself.) You simply don't need error propagation during program execution if misuse fails to compile.



    That example code is incomplete and/or wrong; you can't create any instances of `RadioStatistics' because the constructor is `private' but no instances are created on behalf of `singleton<?>'.

    That example code doesn't cover the major "use case" for "Singleton", global point of unique access; as you said, you can create a "scoped singletons on the stack" so code foreign to the first code called which creates a "scoped singletons on the stack" likely crashes because the copy constructor the exception mechanism calls gets an invalid instance of the object to copy. (You can't `throw' an object by reference. You can `throw' a pointer to an object which is just a value.)

    That example code doesn't solve the "Construction/Destruction Order Fiasco" so can't safely be used within `static' or `global' objects; you could create another layer, but you'd be using a "Singleton" class from within the mechanism solving the problem which is silly.

    That example code pretends to be a value class with normal semantics which is the worst possible thing for a "Singleton" class; the `singleton<?>' class should have a `protected' constructor and client classes should have a `private' constructor otherwise you don't actually have a "Singleton". (I maintain that not having a "Singleton" is a good idea.)



    Your destructor for `singleton<?>' hasn't "unattached" itself so other objects being "alive" at the moment is the least of your worries; you never release ownership of the "Singleton" class contract so other code, or the same code executing at a different time, allocating (stack) a new instance of your completely fake "Singleton" raises an exception which calls a copy constructor on a DEAD object. (I apologize for the emphasis, but I wanted to be absolutely clear on the many problems with this example code.)



    If you are creating an object several times, you do not have a "Singleton" class (Again, I advise not having a "Singleton" class, but the point is, you would not have one if you wanted one.), and as before, using this class repeatedly over different points of allocation for the same client simply breaks.

    Yes, indeed, designing a generic "Singleton" class template that covers all the important bases safely is easy, but you haven't done it, nor have you, given your description, intended to create a "Singleton", and at the end of the day, most people shouldn't create a generic "Singleton" class templates; the existence of such a facility will increase the misuse of the already overused and misused "Singleton" pattern, and we don't want that.

    Soma
    Well, while you are absolutely right about the inability to "throw by reference" (no excuse, but I was tired at the time that I formulating that thought!), you've obviously missed the important points of my post. Unfortunately, I really haven't got the energy to engage in a nit-picking debate with you, so we'll just have to "agree to disagree" this time, I suppose...
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Class vs. Namespace as Singleton
    By eros in forum C++ Programming
    Replies: 0
    Last Post: 03-28-2012, 06:07 AM
  2. Singleton Class error
    By anirban in forum C++ Programming
    Replies: 10
    Last Post: 10-28-2010, 06:44 AM
  3. Compiler complaining about my singleton class
    By DavidP in forum C++ Programming
    Replies: 12
    Last Post: 06-09-2009, 02:30 AM
  4. Bug in Singleton class
    By marquito in forum C++ Programming
    Replies: 17
    Last Post: 12-14-2007, 01:02 PM
  5. singleton class problem
    By ... in forum C++ Programming
    Replies: 6
    Last Post: 12-22-2003, 06:16 PM