C++ singleton


 
Thread Tools Search this Thread
Top Forums Programming C++ singleton
# 1  
Old 10-03-2012
C++ singleton

How to write a class that can only be instancialized once?

what about my implementation below?

Code:
#include<iostream>
#include<stdexcept>
using namespace std;

class Singleton
{
public:
 int b;
 Singleton();
private:
    static int num;
};


int Singleton::num = 1;
Singleton::Singleton()
{
    if (num == 0)
        throw runtime_error("Singleton instancialized more than 1 times");
    num--;
}

int main()
{
        Singleton a;
        Singleton b; //here exception occurs
}

# 2  
Old 10-03-2012
The typical schemis is to make the constructor private, and provide a public function that sees if an instance has already been instantiated, constructs it if it's not been, and then returns it. This way, no other class can even attempt to instantiate your class a second time, since the constructor is private. Always better to find out problems at compile-time rather than run-time (IMHO).
# 3  
Old 10-04-2012
but if the user use the public function to instantiate a second time, it can also only be detected at run time. Isn't it?
# 4  
Old 10-05-2012
No - make a private static variable that is a pointer to your object type. Make sure it's NULL initially. Then at each request, check if this pointer is NULL - if it is, then no instance of your object has been initialized, so construct one and return it. If it is non-NULL, just return it:

Code:
class Single
{
private:
    static Single *single;  // Initialize to NULL at definition.
    Single();
public:
    static Single *getSingle() {
        if (!single)
            single = new Single();  // Only gets called once, then if() statemenet is false.
        return single;
    }
};

# 5  
Old 10-05-2012
That's good. But what is the backward of my implementation? If I change the static variable num to any other integer such as 3, I can get a class that can only be initialized three times. Isn't it more flexible?
# 6  
Old 10-05-2012
Quote:
Originally Posted by JohnGraham
No - make a private static variable that is a pointer to your object type. Make sure it's NULL initially. Then at each request, check if this pointer is NULL - if it is, then no instance of your object has been initialized, so construct one and return it. If it is non-NULL, just return it:

Code:
class Single
{
private:
    static Single *single;  // Initialize to NULL at definition.
    Single();
public:
    static Single *getSingle() {
        if (!single)
            single = new Single();  // Only gets called once, then if() statemenet is false.
        return single;
    }
};

Not quite. That's just hoping your constructor only gets called once.

Code:
class Single
{
private:
    static Single *single;  // Initialize to NULL at definition.
    Single();
public:
    static Single *getSingle()
    {
        // if we've already created the singleton, no need to spend the time
        // needed to lock and unlock the mutex
        if ( !single )
        {
            static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

            pthread_mutex_lock( &mutex );

            // need to check again in case another thread created the singleton
            // while this thread was blocked waiting for the mutex
            if ( !single )
            {
                single = new Single();  // Only gets called once, then if() statemenet is false.
            }

            pthread_mutex_unlock( &mutex );
        }
        return single;
    }
};

# 7  
Old 10-05-2012
Quote:
That's good. But what is the backward of my implementation? If I change the static variable num to any other integer such as 3, I can get a class that can only be initialized three times. Isn't it more flexible?
Just make an array of pointers - though how you'd decide which one to give out is up to you.


Quote:
Originally Posted by achenle
Not quite. That's just hoping your constructor only gets called once.
Well, it's assuming the class is running in a single-threaded environment, but that brings its own special problems.


Quote:
Originally Posted by achenle
Code:
    static Single *getSingle()
    {
        // if we've already created the singleton, no need to spend the time
        // needed to lock and unlock the mutex
        if ( !single )
        {
            static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

            pthread_mutex_lock( &mutex );

            // need to check again in case another thread created the singleton
            // while this thread was blocked waiting for the mutex
            if ( !single )
            {
                single = new Single();  // Only gets called once, then if() statemenet is false.
            }

            pthread_mutex_unlock( &mutex );
        }
        return single;
    }
};

This is a fairly well-known anti-pattern - please avoid it. In general, any access to a variable protected by a mutex must be protected by that mutex, or reorderings in (i) the code the compiler generates, (ii) cached memory read/writes in the CPU and (iii) competing caches on SMP systems mean your strategy may break.

In this case, in the line "single = new Single()", the compiler is allowed to reorder the instructions in any way it wants, so it is e.g. allowed to set the pointer 'single' to point to the memory location before it's initialized. In this case, the 'if (!single)' code, if run at a certain point in the other thread's execution, would not wait for initialization, be false, and you're suddenly returning a pointer to a potentially uninitialized structure from your function. Also other things - I understood this (I think) when I was learning this stuff, but even if you can (or think you can) refute this, there are many other reasons.

And besides, how much performance do you really expect to get from this?

Also, things get more complicated on SMP systems, so without propper memory barriers (which locking the mutex would give you) you cannot tell if memory read/writes would be reordered or not.

Code:
    static Single *getSingle()
    {
        Single *result;
        static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

        // All accesses to 'single' occur when this mutex is locked.
        pthread_mutex_lock(&mutex);  // Note: Check return value.
        if ( !single )
        {
            single = new Single();  // Only gets called once, then if() statemenet is false.
        }
        result = single;
        pthread_mutex_unlock(&mutex);

        return result;
    }
};

Or, even better, just use the already-supplied pthread_once().
Login or Register to Ask a Question

Previous Thread | Next Thread

3 More Discussions You Might Find Interesting

1. UNIX for Beginners Questions & Answers

AIX errpt : ( E7A89C7D Local adapter disabled after unstable singleton for long time )

Medel : 9117-MMC OS: AIX 6.1 Patch level : 6100-07-04-1216 Hacmp version : HACMP v 6.1.0.8 Oracle : 11.2.0.3 RAC Node : 2 node Dear, my one node server has been restarted early this morning, So, i tried to start HA and Oracle database. after that, the follow error appears at the node... (1 Reply)
Discussion started by: tomato00
1 Replies

2. Programming

C++ abstract (singleton) factory implementation...

I want to create an abstract factory template which will allow me to pass in an "ID" for a subclass and return the singleton instance of that class stored in the factory. It'd be easy to adapt for "multi-ton", but for its present use this isn't necessary. The requirements are: - I don't want... (2 Replies)
Discussion started by: DreamWarrior
2 Replies

3. Programming

What is singleton class ?

hello members, What is singleton class in c++ and in which case we will go with singleton class. Thanks & Regards Rajkumar_g (2 Replies)
Discussion started by: rajkumar_g
2 Replies
Login or Register to Ask a Question