[SOLVED] How can I make a Class be instantiated only ONCE?
-
Supposedly, I have class called MyClass.
MyClass manages multiple widgets of the same kind and SHOULD be the only one managing these widgets.
What I want to achieve is "analogous" to this "thread":http://stackoverflow.com/questions/4087235/how-to-force-my-application-to-open-one-exe-only-qt-linux but in a way that it is just a "Class" and not an application.
The reason for this is that when I instantiate MyClass as:
@MyClass mc;@"mc" will be the only one "MONOPOLIZING" the set of widgets.
Doing this:
@MyClass mc1; \ok
MyClass mc2; \invalid
MyClass mc3; \invalid and so on
.... @The RESTRICTION is that MyClass doesn't have any ctor or dtor so I don't think I can do a "hack" with QSharedMemory or something.
Help Please. Thanks!
-
Sounds like you want to make use of the "Singleton Pattern"? ( "http://www.qtcentre.org/wiki/index.php?title=Singleton_pattern ":http://www.qtcentre.org/wiki/index.php?title=Singleton_pattern)
-
First of all, make the (copy) constructor and the assign-operator of MyClass private or protected (note: constructor can be an empty constructor, if you don't have one yet!), so new instances cannot be created directly. Then add a static public method MyClass::getInstance() which is used to get the pointer to the one and only instance. So this method will create a new instance when no instance was created before, otherwise it just returns the pointer to the already existing instance. You also need a private static variable to store the instance pointer...
@//m_instance is static and private!
MyClass *MyClass::m_instance = NULL;//method is static too, but public!
MyClass* MyClass::getInstance(void)
{
if(m_instance == NULL) m_instance = new MyClass();
return m_instance;
}@ @//TEST
MyClass *ptr1 = MyClass::getInstance();
MyClass *ptr2 = MyClass::getInstance();
MyClass *ptr3 = MyClass::getInstance();
if((ptr1 == ptr2) && (ptr2 == ptr3)) qDebug("It works!")@Ideally the above code should also be guarded with a QMutex to avoid race-conditions in the multi-threaded app!
-
Thanks vidar and MuldeR for the replies and I think this is what I am looking for.
I will be testing these methods :)
-
Keep in mind you will still be able to call getInstance more than once, you will get multiple pointers to the same instance, memory leaks should not be a problem thou, since you are using the one instance in a static context, but you still have checks each and every time, which can be avoided, plus new has some minor overhead and could potentially throw an exception if you are out of memory.
Also, you can, by mistake, call delete on some of the pointers and lose the resource. So instead of a static pointer to the class and dynamic allocation you can simply go for a static instance that is automatically created for the lifetime of the program, and only return a reference to it, since working with references is a little easier and you are also safe from accidental pointer arithmetic and walking off the address of the instance.
@class MyClass {
public:
int getI(){return i;}
void setI(int value){i = value;}
static MyClass & getInstance(){return data;}
private:
MyClass(int value) : i(value){}
MyClass(const MyClass &);
MyClass& operator=(const MyClass &);
int i;
static MyClass data;
};MyClass MyClass::data(7); // the one and only instantiation a.k.a initialization
int main(){
cout << MyClass::getInstance().getI() << endl;
MyClass::getInstance().setI(8);
MyClass &myRef = MyClass::getInstance(); // if you need a shorthand identifier
cout << myRef.getI() << endl;
}@Note that you have to initialize the static member outside of the class but still in the same file, line 14, yes you can, even thou it is private and the constructor is private too.
Worst case scenario is you call delete on the reference, which is possible, but will result in undefined behavior, while it will certainly not delete the actual data, since it is not allocated dynamically in the first place. You get to use the . syntax instead the ->, you cannot delete it and it will be allocated before any code gets executed.
Summary:
-
can't be deleted
-
can't walk off the address with pointer arithmetic
-
can't throw an exception
-
does not do dynamic memory allocation
-
does not check if exists every time
-
use . instead of ->
-
is 100% sure to be allocated
-
-
@
template<typename T>
class meyersSingleton
{
public:
static T& instance()
{
static T theSingleton;
return theSingleton;
}meyersSingleton(meyersSingleton const&) = delete;
meyersSingleton& operator=(meyersSingleton const&) = delete;private:
meyersSingleton(); // ctor hidden
~meyersSingleton(); // dtor hidden
};
@ -
^^^
One quick note - Mayers sure loves C++11, but there is no "= delete" in older compilers, which are still somewhat relevant in Qt.Another note - while this guarantees all instances of meyersSingleton<SomeClass> will always return the same instance of SomeClass, this doesn't prevent instantiating SomeClass on its own as many times as you want. This has different application than preventing a class from being instantiated more than once, which was what the thread is about, if I understand correctly.
Also, having the static member as a static method local is a nice and quick way to ensure thread safety - BUT again, only in C++11.
-
Thanks for replies!
I think singleton is the best way to use in my application since I only need a single global manager class to manage all widgets (small windows in my desktop) and I don't want them to stack above each other and they are all on the top-level.
If there is another option. Please post it here.
Another question: Does it apply when another application uses the same singleton class? Do multiple apps have the same pointer to an instance?I appreciate your answers. Thanks!
-
No, different applications have their own dedicated virtual memory space and even if you pass a raw memory address from one process to another, you won't get the same hardware memory address. This doesn't mean different processes cannot share memory thou, there are plenty of "ways to do it":http://doc.qt.digia.com/qt/ipc.html#shared-memory.
-
[quote author="utcenter" date="1357787580"]^^^
One quick note - Mayers sure loves C++11, but there is no "= delete" in older compilers, which are still somewhat relevant in Qt.
[/quote]these codes should be more compliant to c++11
@
template<typename T>
class meyersSingleton
{
public:
static T& instance()
{
static T theSingleton;
return theSingleton;
}meyersSingleton() = delete;
~meyersSingleton() = delete;
meyersSingleton(meyersSingleton const&) = delete;
meyersSingleton& operator=(meyersSingleton const&) = delete;};
@if your compiler don't support delete
@
template<typename T>
class meyersSingleton
{
public:
static T& instance()
{
static T theSingleton;
return theSingleton;
}private :
meyersSingleton();
~meyersSingleton();
meyersSingleton(meyersSingleton const&);
meyersSingleton& operator=(meyersSingleton const&);};
@bq. Another note - while this guarantees all instances of meyersSingleton<SomeClass> will always return the same instance of SomeClass, this doesn't prevent instantiating SomeClass on its own as many times as you want. This has different application than preventing a class from being instantiated more than once, which was what the thread is about, if I understand correctly.
I don't get it why this class could be constructed since it forbid
the constructor and destructor?bq. Also, having the static member as a static method local is a nice and quick way to ensure thread safety - BUT again, only in C++11.
Dear utcenter, as you said, meyers singleton is thread safe in
c++11(finally), but not c++03 and 98.Please correct me if there are any mistakes, thanks.
-
[quote author="Code_ReaQtor" date="1357789847"]Thanks for replies!
I think singleton is the best way to use in my application since I only need a single global manager class to manage all widgets[/quote]
If you only need one instance of your object, just create only one instance of your object. Singleton should not be used to create a unique instance, it should be used to avoid multiple instance: it is definitely not the same problem. Before implementing it, you should read some of the articles explaining why some consider singleton as an anti-pattern. "Wikipedia article about singleton":http://en.wikipedia.org/wiki/Singleton_pattern#cite_note-1 gives some references.
-
I also recommend to not use a static member.
You will have to use a static method local instead of a static member in order to avoid "initialization order problems":http://www.parashift.com/c++-faq/static-init-order.html, which will otherwise lead to undefined behaviour (mind QCoreApplication).
In addition, you will have to use a static method local instead of a static member in order to lazy-initialize your instance, which is an absolute requirement in Qt to access a large part of QtWidgets and its graphics stack, as they depend on an existing QApplication instance (which is not true at static initialization time).
A static member will also increase your application startup time.
QtWidgets itself is inherently not thread-safe; if you still need thread-safe initialization for your class follow "Q_GLOBAL_STATIC":http://code.woboq.org/qt5/qtbase/src/corelib/global/qglobal.h.html#738 (this is an MSVC issue only, as static method local initialization is always thread-safe in GCC and Clang, be it C++98 or C++11).
And yes, singletons should be considered an anti-pattern, as they violate the single responsibility principle. If you want to make sure that there is just a single instance make the constructor private and friend a factory, which allows only one instance to be created (as in <code>meyersSingleton</code>).
-
[quote author="Lukas Geyer" date="1357810573"]I also recommend to not use a static member.
You will have to use a static method local instead of a static member in order to avoid "initialization order problems":http://www.parashift.com/c++-faq/static-init-order.html, which otherwise will lead to undefined behaviour (mind QCoreApplication).[/quote]
That would be a problem if we made the static member variable an (auto) object. But if we make it a pointer to an object (statically initialized to NULL), as was suggested above, there should be no such problem, right? The object will be created at the moment when getInstance() is called for the very first time, so behavior is well-defined. And if we use a Mutex in that function, as shown in the article linked by vidar, it will even be thread save :-)
Also: If we made the variable an (auto) object rather than a pointer and declare it as a local static variable, the resulting code would absolutely not be thread save! That's because this code:
@void MyClass* MyClass::getInstance(void)
{
static MyClass instance;
return &instance;
}@Would be expanded by the compiler to something (analogously) like:
@void MyClass* MyClass::getInstance(void)
{
static _init = false;
static MyClass instance;if(!_init) { &instance = new MyClass(); /*construct on first call*/ _init = true; } return &instance;
}@
Now it should be easy to spot the race-condition... ("more":http://blogs.msdn.com/b/oldnewthing/archive/2004/03/08/85901.aspx)
--
Only problem I see with the static member variable solution is that the object never gets destroyed - unless we explicitly add a static MyClass:destroyInstance() method and call it at the end of our main() function. Either that or we add some atexit() magic to MyClass:getInstance() to do the clean-up automatically on termination:
@MyClass *MyClass::m_instance = NULL;
MyClass* MyClass::getInstance(void)
{
QMutexLocker lock(&m_mutex);
if(m_instance == NULL)
{
m_instance = new MyClass();
atexit(doCleanup);
}
return m_instance;
}void MyClass::doCleanup(void)
{
QMutexLocker lock(&m_mutex);
if(m_instance != NULL)
{
delete m_instance;
m_instance = NULL;
}
}@ -
[quote author="MuldeR" date="1357818537"]That would be a problem if we made the static member variable an (auto) object. But if we make it a pointer to an object (statically initialized to NULL), as was suggested above, there should be no such problem, right?[/quote]-Yes.
[quote author="MuldeR" date="1357818537"]Also: If we made the variable an (auto) object rather than a pointer and declare it as a local static variable, the resulting code would absolutely not be thread save![/quote]Absolutely. But as said, QtWidgets is not thread-safe at all as well, so the requirement for thread-safety is unlikely, whereas the requirement for defined behaviour and lazy initialization is absolute (which will require the use of a static method local object instead of a static member object).
You will have to add thread-safety when needed (either using a mutex, which is quite costly, or better an atomic test-and-set-ordered instruction as seen in Q_GLOBAL_STATIC, and in case your compiler does not support thead-safe static method local object initialization anyway).
[quote author="MuldeR" date="1357818537"]Only problem I see with the static member variable solution is that the object never gets destroyed - unless we explicitly add a static MyClass:destroyInstance() method and call it at the end of our main() function. Either that or we add some atexit() magic to MyClass:getInstance() to do the clean-up automatically on termination.[/quote]A common solution is to use a thread-safe wrapper instead of the pointer itself, which deletes the object during its destruction.
@
MyClass* MyClass::getInstance(void)
{
QMutexLocker lock(&m_mutex);
if(m_instance == NULL)
{
m_instance = new MyClass();
atexit(doCleanup);
}
return m_instance;
}
@
Be aware that this code already yields undefined behaviour. Due to <code>m_mutex</code> beeing a static member it has to be initialized using <code>QMutex MyClass::m_mutex</code> at global scope, whose initialization order is undefined. If there is another static member which calls <code>MyClass::getInstance()</code> directly or indirectly you are at a 50% chance of using an uninitialized QMutex. You will have to use static method local instead of the static member (<code>QMutex &m_mutex() { static QMutex mutex; return mutex; }</code> be aware that there is no thread-safety required here, as static initialization is always done in a single-threaded context). -
I'm not aware of a better method than making those "global" Mutex'es (auto) objects. We cannot initialize them "lazy", because to initialize a Mutex the "lazy" way at runtime, we'd need another Mutex for protection - leading to an infinite sequence of Mutex'es. We could do a globalInit() early in main(), but that's pretty much the same.
However it should be save to have a global QMutex as (auto) object, because the Mutex will be initialized before the main() function even enters and thus before anybody calls getInstance(). The order doesn't really matter, because all we need is that all global Mutex'es have been initialized when the main() function starts.
Now if we have another global (auto) object, which inside its constructor calls getInstance(), then that's simply a programming mistake. Constructors of global objects really should not try to access other objects! :-O
--
To harden our code against this kind of programming mistake, maybe we could do:
@static QMutex *g_mutex = NULL;
static volatile long g_init = 0L;void globalInit(void)
{
if(_InterlockedCompareExchange(&g_init, -1L, 0L) != 0L)
{
/fatal error: must be called exactly once!/
abort();
}g_mutex = new QMutex(); /*more initialization work*/
_InterlockedCompareExchange(&g_init, 1L, -1L);
}MyClass *getInstance(void)
{
if((g_init != 1L) || !g_mutex)
{
/fatal error: not initialized yet!/
abort();
}QMutexLocker(g_mutex); /* ... */
}
// ------------
int main(...)
{
globalInit();/* ... */ MyClass *ptr = getInstance(); /* ... */
}@
-
You will have to differentiate between static initialization order safety and thread safety.
Static initialization order safety needs not to be thread safe, as there is just a single thread at the time static objects are initialized (before main); you need no mutex. You just need to make sure that an object exists at the time it is accessed.
[quote author="MuldeR" date="1357825548"]Now if we have another global (auto) object, which inside its constructor calls getInstance(), then that's simply a programming mistake. Constructors of global objects really should not try to access other objects![/quote]No, it isn't and yes, they should if they need to. And you will have to beware of it when creating code that is subject to static initialization order (as for instance an accessible static member or a static global).And even if you apply this rule to your local coding guidelines - since when has forbidding making programming mistakes stopped developers doing so? ;-)
Please be aware that I've updated the first answer of the previous post, as I have completely misunderstood your question.
-
[quote author="Lukas Geyer" date="1357824375"]No, your pointer will still be subject to static initialization order problems (the pointer might be read before it has been initialized with NULL), but not to the lazy initialization problem.[/quote]
Just wanted to add that this problem does not exist in practice. The global pointer variable does not actually need to be initialized "actively" - unlike Object's whose constructor needs to be called. The linker will simply assign that variable an address within the executables 'data' section and at this address the correct initial value (NULL in this case) is stored. So the pointer will be NULL already at the moment when the executable's image is loaded into memory by the os's loader... long before any static initializers (in whatever order) are executed.
(I don't know if the C standard really guarantees that behavior. It probably does but I haven't checked. Anyway, it's at least what all practical compilers will do)
There even exist a special section (BSS) for zero-initialized variables:
http://en.wikipedia.org/wiki/.bss--
[quote author="Lukas Geyer" date="1357824375"]And even if you apply this rule to your local coding guidelines – since when has forbidding making programming mistakes stopped developers doing so? ;-)[/quote]
Well, with the global initialization function (see previous post) or some similar approach we could enforce the correct use. It adds some more complexity though...
-
[quote author="MuldeR" date="1357832140"]Just wanted to add that this problem does not exist in practice.[/quote]No, it doesn't. I stand corrected, the initial answer was correct (I somehow had non-exclipt initalized in mind).
[quote]Objects with static storage duration (3.7.1) shall be zero-initialized (8.5) before any other initialization takes place. Zero-initialization and initialization with a constant expression are collectively called static initialization; all other initialization is dynamic initialization. Objects of POD [plain old data] types (3.9) with static storage duration initialized with constant expressions (5.19) shall be initialized before any dynamic initialization takes place. Objects with static storage duration defined in namespace scope in the same translation unit and dynamically initialized shall be initialized in the order in which their definition appears in the translation unit.[/quote]
[quote author="MuldeR" date="1357832140"]Well, with the global initialization function (see previous post) or some similar approach we could enforce the correct use. It adds some more complexity though...[/quote]Or just create static initialization order aware code, so it is in fact a non-issue. ;-) -
[quote author="Lukas Geyer" date="1357835466"][quote author="MuldeR" date="1357832140"]Just wanted to add that this problem does not exist in practice.[/quote]No, it doesn't. I stand corrected, the initial answer was correct.
[quote]Objects with static storage duration (3.7.1) shall be zero-initialized (8.5) before any other initialization takes place. Zero-initialization and initialization with a constant expression are collectively called static initialization; all other initialization is dynamic initialization. Objects of POD [plain old data] types (3.9) with static storage duration initialized with constant expressions (5.19) shall be initialized before any dynamic initialization takes place. Objects with static storage duration defined in namespace scope in the same translation unit and dynamically initialized shall be initialized in the order in which their definition appears in the translation unit.[/quote][/quote]???
First you said there may be a problem in my getInstance() method because the pointer (global and static) may not have been initialized to NULL (zero) yet when that function is called. I then tried to explain why that problem doesn't exist in practice. Now you show an excerpt from the standard which proves exactly my point. But if I understand your post correctly, you still think there is a problem?
Your excerpt clearly says: Objects of POD [plain old data] types with static storage duration initialized with constant expressions shall be initialized before any dynamic initialization takes place. According to that, the "instance" pointer gets initialized to NULL before any global Object is constructed (as the latter would be a "dynamic initialization") - and therefore before anything might potentially try to call the getInstance() method. The only thing that might potentially call getInstance() even before the main() function is entered would be a "dynamic" initializer, e.g. a constructor of a global object. And this can happen only after static initialization has been done.