implicit sharing when using references of QSharedDataPointer. can't understand the behaviour... code snipet with output ;)
-
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 ¶ms) : _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 ¶mToSet) { 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 withQSharedDataPointer
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 :)
-
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.