How to implement a singleton provider for qmlRegisterSingletonType?

10,080

Solution 1

it just feels wrong to write a singleton provider which returns a new instance when called from different cpp files. So I tried an own implementation where I use a static class member to return the instance

Quote from documentation to qmlRegisterSingletonType function:

NOTE: A QObject singleton type instance returned from a singleton type provider is owned by the QML engine. For this reason, the singleton type provider function should not be implemented as a singleton factory.

It means that such behaviour when singleton type provider returns a new instance is done by intention despite the fact that it, as you have noted, looks weird at first glance. So, your class implementation should look something like below:

class MySingleton: public QObject
{
    Q_OBJECT
    Q_DISABLE_COPY(MySingleton)

    MySingleton() {}

public:
    static QObject *qmlInstance(QQmlEngine *engine, QJSEngine *scriptEngine)
    {
        Q_UNUSED(engine);
        Q_UNUSED(scriptEngine);

        return new MySingleton;
    }
};

Moreover, you should use ampersand for MySingleton::qmlInstance since it is a member method. See this for more info. Then registration should look so:

qmlRegisterSingletonType<MySingleton>(uri, 1, 0, "MySingleton", &MySingleton::qmlInstance);

Solution 2

The problem is (your second example) that you have to initialize your m_instance static member variable. You can do it in mysingleton.cpp file, like:

QObject * MySingleton::m_instance = 0;
Share:
10,080
FourtyTwo
Author by

FourtyTwo

Interested in C++, Qt and embedded software.

Updated on June 27, 2022

Comments

  • FourtyTwo
    FourtyTwo about 2 years

    I want to use C++ Classes as Singleton instances in QML and figured that I have to register them with qmlRegisterSingletonType. This function requires a function which provides an instance of the registered C++ class. I am using latest Qt 5.3.1 with included MinGW 4.8 on Windows.

    The documentation shows the following example of a provider function:

    static QJSValue example_qjsvalue_singletontype_provider(QQmlEngine *engine, 
        QJSEngine *scriptEngine)
    {
        Q_UNUSED(engine)
    
        static int seedValue = 5;
        QJSValue example = scriptEngine->newObject();
        example.setProperty("someProperty", seedValue++);
        return example;
    }
    

    I tried to use this, but I get a compiler warning when I define such a function outside of class scope in a header, occurring in another cpp file including the same header:

    warning: 'QObject* example_qjsvalue_singletontype_provider(QQmlEngine*, 
    QJSEngine*)' defined but not used [-Wunused-function]
    

    Furtheron, it just feels wrong to write a singleton provider which returns a new instance when called from different cpp files. So I tried an own implementation where I use a static class member to return the instance:

    // mysingleton.h
    class MySingleton: public QObject
    {
        Q_OBJECT
        Q_DISABLE_COPY(MySingleton)
    public:
        static QObject *qmlInstance(QQmlEngine *engine, QJSEngine *scriptEngine) {
    
            Q_UNUSED(engine)
            Q_UNUSED(scriptEngine)
    
            if(!m_instance)
            {
                m_instance = new MySingleton();
            }
            return m_instance;
        }
        MySingleton(QObject* parent = 0)
            :QObject(parent)
        {}
    private:
        static QObject* m_instance;
    };
    

    I tried to register this using ...

    qmlRegisterSingletonType<MySingleton>(uri, 1, 0, "MySingleton", 
    MySingleton::qmlInstance);
    

    This solution doesn't work either, I am getting linker errors:

    release/main.o:main.cpp:
    (.text$_ZN11MySingleton11qmlInstanceEP10QQmlEngineP9QJSEngine[__ZN11MySingleton11
    qmlInstanceEP10QQmlEngineP9QJSEngine]+0x42): undefined reference to 
    `MySingleton::m_instance'
    

    What is the correct solution to provide the required Singleton instance 1) with a function outside of class scope and 2) with a class member function?

    Why does the example suggest to create a new instance on every call of the provider function?

  • FourtyTwo
    FourtyTwo over 9 years
    I never saw the second code snippet in real code. What does this actually do?
  • Bob
    Bob over 4 years
    Where in the docs does it say you have to or even can template the call qmlRegisterSingletonType?
  • Dmitry Volosnykh
    Dmitry Volosnykh over 4 years
    @Bob I have update the link to point to a correct method overload.