What is the singleton class in QT? and questions about this class

I have a doubts about this class. With the singleton class you can embed objects without having to call them by issuing the singleton instance. Does anyone know more about this class or can you make a simple example to better understand its function?

 3
Author: Perl, 2016-10-18

3 answers

Regarding the Singleton.

A Singleton is an object that allows the existence of a single instance . Most programming languages do not have Singletons natively1, so they use the constructs at their disposal to create them.

The Singleton , on the other hand, is a design pattern that does not enjoy great popularity and is regarded as an anti-design pattern not because it is inherently malicious if not because it is usually used poorly or in situations where it is not necessary and usually complicates the code (especially in situations of concurrency) and the tests associated with it. In addition, a Singleton is similar to a global variable which is considered a bad practice.

Singleton in Qt.

Qt does not have a Singleton class as part of its facilities, but gives a guide to create one using their own facilities:

template <class T>
class Singleton
{
public:
    static T& instance()
    {
        qCallOnce(init, flag);
        return *tptr;
    }

    static void init()
    {
        tptr.reset(new T);
    }

private:
    Singleton() {};
    ~Singleton() {};
    Q_DISABLE_COPY(Singleton)

    static QScopedPointer<T> tptr;
    static QBasicAtomicInt flag;
};

The above template is a Adapter to transform an arbitrary object into Singleton; it requires calling the static function instance() (common in Singletons implementations) which delegates to the template function qCallOnce:

template <class Function>
inline static void qCallOnce(Function func, QBasicAtomicInt& flag)
{
    int protectFlag = flag.fetchAndStoreAcquire(flag.load());

    if (protectFlag == CO_Finished)
        return;
    if (protectFlag == CO_Request && flag.testAndSetRelaxed(protectFlag,
                                                       CO_InProgress)) {
        func();
        flag.fetchAndStoreRelease(CO_Finished);
    }
    else {
        do {
            QThread::yieldCurrentThread();
        }
        while (!flag.testAndSetAcquire(CO_Finished, CO_Finished));
    }
}

Whose mission is to ensure that the function passed as a template parameter is called once and only once, even from different threads (thanks Peregring-lk). The example of using this suggested Singleton by the QT team is as follows:

struct mi_objeto { void f() { std::cout << this << '\n'; } };

Singleton<mi_objeto>::instance().f();
mi_objeto &mo = Singleton<mi_objeto>::instance();
mo.f();

The above code will show the same memory address twice because on both occasions we have accessed the same instance of mi_objeto; but this approximation will not prevent us from making additional instances of mi_objeto without using the Singleton:

Singleton<mi_objeto>::instance().f(); // Accedemos al Singleton
mi_objeto &mo = Singleton<mi_objeto>::instance(); // Referenciamos el Singleton
mi_objeto a, b, c, d, e; // Creamos 5 instancias adicionales de mi_objeto
mo.f();

So mi_objeto won't be a Singleton, but Singleton<mi_objeto> will.

Singleton in C++.

The QT approximation is not the only one for creating a Singleton, since C++11 it is relatively simple to create a class that behaves like a Singleton.

Singleton Class.

class Neo_The_Chosen_One // Solo puede haber uno!!
{
    static Neo_The_Chosen_One singleton;

public:
    Neo_The_Chosen_One(Neo_The_Chosen_One &&) = delete;
    Neo_The_Chosen_One(const Neo_The_Chosen_One &) = delete;
    Neo_The_Chosen_One &operator=(const Neo_The_Chosen_One &) = delete;

    static Neo_The_Chosen_One &instance()
    {
        return singleton;
    }
};

Neo_The_Chosen_One Neo_The_Chosen_One::singleton{};

The code above allows one and only one instance of the object Neo_The_Chosen_One, since its constructor is private and has the copy/move constructor and copy operator cleared, all these uses would be incorrect:

// Error, constructor privado.
Neo_The_Chosen_One mr_anderson_1;
// Error, constructor de copia borrado.
Neo_The_Chosen_One mr_anderson_2 { Neo_The_Chosen_One::instance() };
// Error, operador de copia borrado.
Neo_The_Chosen_One mr_anderson_3 = Neo_The_Chosen_One::instance();

The following uses would be correct:

Neo_The_Chosen_One &mr_anderson_4 { Neo_The_Chosen_One::instance() };
Neo_The_Chosen_One &mr_anderson_5 = Neo_The_Chosen_One::instance();

References mr_anderson_4 and mr_anderson_5 will point to the same instance (the only allowed) and therefore will be dangerous to use on concurrent systems.

But if we don't care that more than one instance of the same class can exist (and concurrency problems) we can use a template variable or the clause extern with the same results and with less Code:

Singleton variable template.

struct mi_objeto { void f() { std::cout << this << '\n'; } };
template <int DUMMY = 0> mi_objeto objeto;

The template variable objeto works as a Singleton (there will only be one object instance for each value DUMMY) and it can be used like the singletons we have already seen:

mi_objeto &mo { objeto<> };
mo.f();
objeto<>.f();

This approximation has the peculiarity that we can have several Singleton of mi_objeto for each value we give to the template parameter DUMMY, this is due to the unique definition rule of C++ and how this rule works with templates, according to the C++standard (highlighting and translation mine):

3.2 single definition rule

  1. If it requires exactly a definition of a class in a translation unit if that class is used so that its type needs to be complete.

    [...]

  2. There can be more than one definition of the type of a class (Clause 9), enumerated type (7.2), inline function with external link (7.1.2), template class (Clause 14), non-static template function (14.5.6), member data of a template class (14.5.1.3), member function of a template class (14.5.1.1), or template specialization for which some template parameters are not specified (14.7, 14.5.5) in a program where each definition appears in different translation units , [...]

    [...]

    If D is a template and is defined in more than one translation unit, [...], will then behave as if there is a single definition of D.

Singleton global variable.

The Singleton behaves like a global variable (that's why you win so many enemies) so a global variable is essentially a Singleton. We can get the characteristics of a Singleton using the qualifier extern:

// mi_objeto.hpp
struct mi_objeto { void f() { std::cout << this << '\n'; } };
// mi_objeto.cpp
mi_objeto singleton{};
// Archivo1.hpp
#include "mi_objeto.hpp"
extern mi_objeto singleton;
// Archivo2.hpp
#include "mi_objeto.hpp"
extern mi_objeto singleton;

In the example above, the instance of mi_objeto called singleton will behave like a Singleton; i.e.: both Archivo1.hpp and Archivo2.hpp will access the same instance of mi_objeto call singleton; for this to work all statements of singleton have to be extern except one (if we don't get a binding error).


1the only one I know that from Native sporte to singleton is Kotlin .

 5
Author: PaperBirdMaster, 2016-10-20 07:35:01

Singleton is a design pattern, your idea is that there exists a single instance of that object in question and it can be used globally without allowing to create an instance again. To prevent other classes from creating instances, the protected and private access modifiers are taken care of.

I'm going to leave you a link of a PDF in Spanish that explains in detail what it consists of with ' qt

Pdf Singleton + Qt '

 3
Author: sioesi, 2016-10-27 15:12:58

Is a class that only administers one instance. The most common example is the Class QApplication.

We can only do QApplication app; and to access the single instance ("Singleton" pattern) we use QApplication::instance() anywhere in our code and return the pointer to the single instance.

 1
Author: StvKrl, 2018-09-21 12:50:14