Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. implicit sharing when using references of QSharedDataPointer. can't understand the behaviour... code snipet with output ;)

implicit sharing when using references of QSharedDataPointer. can't understand the behaviour... code snipet with output ;)

Scheduled Pinned Locked Moved Unsolved General and Desktop
3 Posts 3 Posters 301 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • mbruelM Offline
    mbruelM Offline
    mbruel
    wrote on last edited by
    #1

    Hi guys,
    well:

    • I've my Main object that holds the SharedParams of the apps. => I initiate an empty SharedParams = QSharedDataPointer<Params>;
    • But it has to load them from a config file or the command line using static functions. So I was thought ok, lets pass a reference of the my SharedParams and it would fill it.
    • But during the process I'm creating a first User that will get a copy of the Main SharedParams without doing any modification for now. It could in the future and I'd expect its instance to detach from the Main one.

    Here is a piece of code that kind of illustrate what I want to do:

    #include <QDebug>
    #include <QSharedData>
    #include <QSharedDataPointer>
    
    class Params;
    using SharedParams = QSharedDataPointer<Params>;
    
    class Params : public QSharedData
    {
        friend class ConfigLoader; // direct access to set the attributes
    public:
        Params() : QSharedData(), _attrib("TO BE SET")
        {
            qDebug() << "[Params()] First creation : _attrib: " << _attrib << ", src addr: "
                     << QString("0x%1").arg(reinterpret_cast<quintptr>(this), QT_POINTER_SIZE * 2, 16, QChar('0'));
        }
    
        Params(Params const &o) : QSharedData(o), _attrib("Detached Version")
        {
            qDebug() << "[Params(const &)] oups... copy on write! _attrib: " << _attrib << " src addr: "
                     << QString("0x%1").arg(reinterpret_cast<quintptr>(&o), QT_POINTER_SIZE * 2, 16, QChar('0'))
                     << " detached new addr: "
                     << QString("0x%1").arg(reinterpret_cast<quintptr>(this), QT_POINTER_SIZE * 2, 16, QChar('0'));
        }
        Params(Params &&o) = delete;
    
        QString const &attrib() const
        {
            qDebug() << "[Params::attrib] src addr: "
                     << QString("0x%1").arg(reinterpret_cast<quintptr>(this), QT_POINTER_SIZE * 2, 16, QChar('0'));
    
            return _attrib;
        }
    
    private:
        QString _attrib;
    };
    
    class User
    {
        SharedParams _params;
    
    public:
        User(SharedParams const &params) : _params(params) { }
        QString const &attrib() const
        {
            qDebug() << "[User::attrib] Params addr: "
                     << QString("0x%1").arg(reinterpret_cast<quintptr>(_params.constData()),
                                            QT_POINTER_SIZE * 2,
                                            16,
                                            QChar('0'));
            return _params->attrib();
        }
    };
    
    class ConfigLoader
    { //!< pure static class
        ConfigLoader() = delete;
        Q_DISABLE_COPY_MOVE(ConfigLoader);
    
    public:
        static User *loadParamsAndCreateFirstUser(SharedParams &paramToSet)
        {
            paramToSet->_attrib = "Attrib loaded :)";
            User *pUser         = new User(paramToSet);
            return pUser;
        }
    };
    
    int main(int argc, char *argv[])
    {
        // 1.: The main app should hold the Params
        // but it needs to loaded by a static class method
        // that will create the first user that would implicitly share the Params
        SharedParams mainParam(new Params);
        qDebug() << "1.: from main: Params->attrib(): " << mainParam->attrib();
    
        // 2.: use a function to load the values of the Params
        // that will then be implicitly shared with different users
        // those will either keep it as it is or detach to have their own version
        //
        // This loading function will create the first user after loading the params
        User *user1 = ConfigLoader::loadParamsAndCreateFirstUser(mainParam);
        qDebug() << "2.: user1->attrib(): " << user1->attrib();
    
        // 3.: The main user wants to use its Params that should be loaded
        qDebug() << "3.: from main: Params->attrib(): " << mainParam->attrib();
    
        return 0;
    }
    

    And here is my output:

    15:42:20: Starting /home/mb/Documents/github/build-testImplicitSharing-Desktop_Qt_6_4_0_GCC_64bit-Debug/testImplicitSharing_v1...
    [Params()] First creation : _attrib:  "TO BE SET" , src addr:  "0x0000563d29c988b0"
    [Params::attrib] src addr:  "0x0000563d29c988b0"
    1.: from main: Params->attrib():  "TO BE SET"
    [User::attrib] Params addr:  "0x0000563d29c988b0"
    [Params::attrib] src addr:  "0x0000563d29c988b0"
    2.: user1->attrib():  "Attrib loaded :)"
    [Params(const &)] oups... copy on write! _attrib:  "Detached Version"  src addr:  "0x0000563d29c988b0"  detached new addr:  "0x0000563d29c988e0"
    [Params::attrib] src addr:  "0x0000563d29c988e0"
    3.: from main: Params->attrib():  "Detached Version"
    15:42:20: /home/mb/Documents/github/build-testImplicitSharing-Desktop_Qt_6_4_0_GCC_64bit-Debug/testImplicitSharing_v1 exited with code 0
    

    Why is it detaching for the Main object and not for the User? Is it random? why both don't detached? Kind of lost...
    I've done another version closer than my usecase that doesn't detach... I can't figure it out. I can post it later if some are interested and if I first understand the behaviour of this simple use case.

    After few hours adding traces on my program to finally decide to narrow down the issue and do a snippet to ask here, maybe understand myself... I've just switched to QExplicitlySharedDataPointer that are less a pain!... When my Users will want to detach, they'll do it explicitely.
    But I'm curious and disappointed to not understand why I can't manage to do it with QSharedDataPointer

    Anybody has a bit of time to explain me what's wrong with my approach? is it completely a wrong way to use QSharedDataPointer? or is it just a silly detail I'm missing?

    Thanks in advance :)

    JoeCFDJ 1 Reply Last reply
    0
    • SGaistS Offline
      SGaistS Offline
      SGaist
      Lifetime Qt Champion
      wrote on last edited by
      #2

      Hi,

      I think you're "doing it wrong". AFAIK, QSharedDataPointer and QSharedData are supposed to be internal to the class that implement implicit sharing not floating around.
      Your static method should create and configure the initial user but should not care about the internal handling of its data.

      Interested in AI ? www.idiap.ch
      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

      1 Reply Last reply
      1
      • mbruelM mbruel

        Hi guys,
        well:

        • I've my Main object that holds the SharedParams of the apps. => I initiate an empty SharedParams = QSharedDataPointer<Params>;
        • But it has to load them from a config file or the command line using static functions. So I was thought ok, lets pass a reference of the my SharedParams and it would fill it.
        • But during the process I'm creating a first User that will get a copy of the Main SharedParams without doing any modification for now. It could in the future and I'd expect its instance to detach from the Main one.

        Here is a piece of code that kind of illustrate what I want to do:

        #include <QDebug>
        #include <QSharedData>
        #include <QSharedDataPointer>
        
        class Params;
        using SharedParams = QSharedDataPointer<Params>;
        
        class Params : public QSharedData
        {
            friend class ConfigLoader; // direct access to set the attributes
        public:
            Params() : QSharedData(), _attrib("TO BE SET")
            {
                qDebug() << "[Params()] First creation : _attrib: " << _attrib << ", src addr: "
                         << QString("0x%1").arg(reinterpret_cast<quintptr>(this), QT_POINTER_SIZE * 2, 16, QChar('0'));
            }
        
            Params(Params const &o) : QSharedData(o), _attrib("Detached Version")
            {
                qDebug() << "[Params(const &)] oups... copy on write! _attrib: " << _attrib << " src addr: "
                         << QString("0x%1").arg(reinterpret_cast<quintptr>(&o), QT_POINTER_SIZE * 2, 16, QChar('0'))
                         << " detached new addr: "
                         << QString("0x%1").arg(reinterpret_cast<quintptr>(this), QT_POINTER_SIZE * 2, 16, QChar('0'));
            }
            Params(Params &&o) = delete;
        
            QString const &attrib() const
            {
                qDebug() << "[Params::attrib] src addr: "
                         << QString("0x%1").arg(reinterpret_cast<quintptr>(this), QT_POINTER_SIZE * 2, 16, QChar('0'));
        
                return _attrib;
            }
        
        private:
            QString _attrib;
        };
        
        class User
        {
            SharedParams _params;
        
        public:
            User(SharedParams const &params) : _params(params) { }
            QString const &attrib() const
            {
                qDebug() << "[User::attrib] Params addr: "
                         << QString("0x%1").arg(reinterpret_cast<quintptr>(_params.constData()),
                                                QT_POINTER_SIZE * 2,
                                                16,
                                                QChar('0'));
                return _params->attrib();
            }
        };
        
        class ConfigLoader
        { //!< pure static class
            ConfigLoader() = delete;
            Q_DISABLE_COPY_MOVE(ConfigLoader);
        
        public:
            static User *loadParamsAndCreateFirstUser(SharedParams &paramToSet)
            {
                paramToSet->_attrib = "Attrib loaded :)";
                User *pUser         = new User(paramToSet);
                return pUser;
            }
        };
        
        int main(int argc, char *argv[])
        {
            // 1.: The main app should hold the Params
            // but it needs to loaded by a static class method
            // that will create the first user that would implicitly share the Params
            SharedParams mainParam(new Params);
            qDebug() << "1.: from main: Params->attrib(): " << mainParam->attrib();
        
            // 2.: use a function to load the values of the Params
            // that will then be implicitly shared with different users
            // those will either keep it as it is or detach to have their own version
            //
            // This loading function will create the first user after loading the params
            User *user1 = ConfigLoader::loadParamsAndCreateFirstUser(mainParam);
            qDebug() << "2.: user1->attrib(): " << user1->attrib();
        
            // 3.: The main user wants to use its Params that should be loaded
            qDebug() << "3.: from main: Params->attrib(): " << mainParam->attrib();
        
            return 0;
        }
        

        And here is my output:

        15:42:20: Starting /home/mb/Documents/github/build-testImplicitSharing-Desktop_Qt_6_4_0_GCC_64bit-Debug/testImplicitSharing_v1...
        [Params()] First creation : _attrib:  "TO BE SET" , src addr:  "0x0000563d29c988b0"
        [Params::attrib] src addr:  "0x0000563d29c988b0"
        1.: from main: Params->attrib():  "TO BE SET"
        [User::attrib] Params addr:  "0x0000563d29c988b0"
        [Params::attrib] src addr:  "0x0000563d29c988b0"
        2.: user1->attrib():  "Attrib loaded :)"
        [Params(const &)] oups... copy on write! _attrib:  "Detached Version"  src addr:  "0x0000563d29c988b0"  detached new addr:  "0x0000563d29c988e0"
        [Params::attrib] src addr:  "0x0000563d29c988e0"
        3.: from main: Params->attrib():  "Detached Version"
        15:42:20: /home/mb/Documents/github/build-testImplicitSharing-Desktop_Qt_6_4_0_GCC_64bit-Debug/testImplicitSharing_v1 exited with code 0
        

        Why is it detaching for the Main object and not for the User? Is it random? why both don't detached? Kind of lost...
        I've done another version closer than my usecase that doesn't detach... I can't figure it out. I can post it later if some are interested and if I first understand the behaviour of this simple use case.

        After few hours adding traces on my program to finally decide to narrow down the issue and do a snippet to ask here, maybe understand myself... I've just switched to QExplicitlySharedDataPointer that are less a pain!... When my Users will want to detach, they'll do it explicitely.
        But I'm curious and disappointed to not understand why I can't manage to do it with QSharedDataPointer

        Anybody has a bit of time to explain me what's wrong with my approach? is it completely a wrong way to use QSharedDataPointer? or is it just a silly detail I'm missing?

        Thanks in advance :)

        JoeCFDJ Offline
        JoeCFDJ Offline
        JoeCFD
        wrote on last edited by
        #3

        @mbruel Is not std::shared_ptr easier to use?

        1 Reply Last reply
        0

        • Login

        • Login or register to search.
        • First post
          Last post
        0
        • Categories
        • Recent
        • Tags
        • Popular
        • Users
        • Groups
        • Search
        • Get Qt Extensions
        • Unsolved