Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Subclassing QModelIndex - private constructor?



  • Hey

    I'm in need of extending QModelIndex with a more "specific" functions, but as far as I can tell its constructors are private, and I can't set post creation column/row/model/etc/etc. How can I subclass that object and add extra members/functions to it?

    TIA.


  • Qt Champions 2019

    There is no need to derive from QModelIndex, therefore it's forbidden.



  • Well, I'd like to provide a precise object member rather than the internalPointer, as I'm struggling to get it to work with shared_ptr<treeItem> pointers and as such I need to control destructor/constructor/extra functions etc. Why can't we extend modelIndex?


  • Qt Champions 2017

    Y do u need extra functions in Qmodelindex ? It is transient. May be we can do same thing somewhere else ?



  • @dheerendra said in Subclassing QModelIndex - private constructor?:

    Y do u need extra functions in Qmodelindex ? It is transient. May be we can do same thing somewhere else ?

    Well I've been trying to get my abstract model system to work with sharedPtrs but I'm getting some bad results when I try to retrieve the item back from the QModelIndex. I was hoping I can subclass it and just add the needed 1 function&member to solve the issue.

    Here is more on the subject > https://forum.qt.io/topic/96862/qabstractitemmodel-shared_ptr-issue-itemfromindex/6

    Say if I wish to create QModelIndex(0,0,sharedPtr) I need to pass sharedPtr as & so &sharedPtr, but that is a RAW pointer to shared_ptr in that function, which means that once function ends, that pointer gets deleted and my raw pointer now points in to emtiness, which then when I try to do statitc_cast end up being being bad object and I get lots of null/bad memory results.

    I was hoping to give Qt QmodelIndex a sharedPtr.get() for QT to be happy, but at the same time keep a sharedPtr as a member in my inherited class so that at later date when I do itemFromIndex() I can retrieve the correct shared_ptr/data.


  • Qt Champions 2019

    Don't use shared pointers there and you're fine. Or just store an index in the void* which you can map to your desired shared ptr



  • I need to use shared_ptrs as we wish to expose the tree hierarchy to python via pybind11 which requires shared_ptrs.

    Storing an index in the void* sounds interesting, essentially creating another "temporary ModelIndex alike object" that can be used to retrieve my data structure easier. The only problem I have with that is that, when QmodelIndex is deleted, how do I delete the object that the QmodelIdnex had stored in its void* ? Does QmodelIndex provide any function call on delete or something like that?

    Hmm the more I think about it, perhaps I can store that item in treeItem itself mhmmm but that also poses some dangers, Esentially shared_ptr item storing shared_ptr to itself within itself as member...


  • Qt Champions 2019

    @Dariusz said in Subclassing QModelIndex - private constructor?:

    when QmodelIndex is deleted

    A QModelIndex does not store anything so there can't be deleted anything when a QModelIndex is deleted. A QModelIndex just holds information about a cell and how to get to the underlying data.



  • @Christian-Ehrlicher Given that you store underlying data in vector as std::shared_ptr<treeItem>, how would you pass that to QModelIndex&retrieve it later so that shared_ptr count gets properly managed and you can work with it?
    ItemFromIndex() etc?

    Currently I'm using createIndex(row,col,sharedPtr.get()), but that breaks in many cases for some weird reasons I cant track down :- (


  • Qt Champions 2019

    Since the QModelIndex does not store any data but just points to the data it a plain pointer is ok.



  • @Christian-Ehrlicher said in Subclassing QModelIndex - private constructor?:

    Since the QModelIndex does not store any data but just points to the data it a plain pointer is ok.

    Well can it store shared_ptr ?


  • Qt Champions 2017

    @Dariusz said in Subclassing QModelIndex - private constructor?:

    Well can it store shared_ptr ?

    No.


  • Qt Champions 2019

    @Dariusz said in Subclassing QModelIndex - private constructor?:

    Well can it store shared_ptr ?

    Once again: A QModelIndex does not store the data so even it you could store a pointer there it would be the wrong way.



  • @Christian-Ehrlicher It stores a pointer to data node, In Qt native case its QStandardItem*. I'm trying to store the same thing but my objects are done via shared_ptr instead of raw pointers.

    So again, I kinda need to extend the class or else a way to pass shared_ptr to the void*adata parameter/quintptr.

    @kshegunov Is that not good enough reason to expose the constructor to allow users to subclass the QModelIdnex class to allow for a work around to store it?


  • Qt Champions 2017

    @Dariusz said in Subclassing QModelIndex - private constructor?:

    @Christian-Ehrlicher It stores a pointer to data node

    First of all, it stores an opaque pointer, which can be any pointer.

    I'm trying to store the same thing but my objects are done via shared_ptr instead of raw pointers.

    Secondly, this is not a pointer! This is an object that aggregates a pointer. An object, no matter what it contains, isn't a pointer itself.

    So again, I kinda need to extend the class or else a way to pass shared_ptr to the void*adata parameter/quintptr.

    You can't and you will not. If you want to reference a list of shared pointers, put them in a vector, and store the index of the element inside the model index. When you need to get the shared pointer, take the index of the element from the model index and get the shared pointer from the vector.

    @kshegunov Is that not good enough reason to expose the constructor to allow users to subclass the QModelIdnex class to allow for a work around to store it?

    No. It was already said that a model index does not and will not store data directly. It references data that's someplace else, that is - somewhere you've put it. It has 2 constructors to facilitate that:

    1. one that takes a void * - a generic pointer to something
    2. one that takes an integer - a generic index to something

    It is your responsibility to keep and manage the data.



  • @kshegunov said in Subclassing QModelIndex - private constructor?:

    @Dariusz said in Subclassing QModelIndex - private constructor?:

    @Christian-Ehrlicher It stores a pointer to data node

    First of all, it stores an opaque pointer, which can be any pointer.

    Except it cant store shared_ptr ?

    I'm trying to store the same thing but my objects are done via shared_ptr instead of raw pointers.

    Secondly, this is not a pointer! This is an object that aggregates a pointer. An object, no matter what it contains, isn't a pointer itself.

    Hmm yeap true. Still it has "pointer" written all over it and as far as I can tell its raw 2.0 pointer. Even Qt has its own implementation of QSharedPtr as far as I remember. Perhaps they all should change the naming to call it shared_wrapper/smart_wrapper ? / anyway waving off the topic here.

    So again, I kinda need to extend the class or else a way to pass shared_ptr to the void*adata parameter/quintptr.

    You can't and you will not. If you want to reference a list of shared pointers, put them in a vector, and store the index of the element inside the model index. When you need to get the shared pointer, take the index of the element from the model index and get the shared pointer from the vector.

    Not sure how much performance that will yeld, I'm looking at milions of objects, if I need to keep making/deleting vectors I will lose cycles on just handling the massive vector list. Not to mention if I want to delete 500k objects, then I need to filter over the vector to clear objects there too... with shared_ptr/QModelIndex, the second QModelIndex dies and if its the last index then the object would get deleted too.

    @kshegunov Is that not good enough reason to expose the constructor to allow users to subclass the QModelIdnex class to allow for a work around to store it?

    No. It was already said that a model index does not and will not store data directly. It references data that's someplace else, that is - somewhere you've put it. It has 2 constructors to facilitate that:

    1. one that takes a void * - a generic pointer to something
    2. one that takes an integer - a generic index to something

    It is your responsibility to keep and manage the data.

    It does not store data no, yes that's correct. But it stored a pointer to the data.
    Right now QStandardModelItem/QStandardItem are based on *Raw pointers. So it's all nice. But if a user(me) wants to use QAbstractItemModel & customItem based on shared_ptr<> then I have no way of using QModelIndex to store/retrieve the internalPointer in a correct format that won't break shared_ptr<>.

    As far as I can tell shared_ptr are being pushed out there to replace raw ptrs so that memory leaks are easier to fix and memory is managed better. Why is it so hard to either expose constructor for qmodelIndex or add a way for it to work with shared_ptr? All its need is std::shared_ptr<void>> - but that needs more hassle, or just expose the constructor from private to public? :/

    Sorry if I'm being a little "Stubborn" but we have the tools to replace qabstractmodel/treeView/item etc. But nothing for ModelIndex...


  • Qt Champions 2019

    @Dariusz said in Subclassing QModelIndex - private constructor?:

    But it stored a pointer to the data.

    No, it does not store anything, you're wrong. A QModelIndex has no ownership on something. A shared_ptr is exactly the opposite - it is a shared ownership to a data structure/object.


  • Qt Champions 2017

    @Dariusz said in Subclassing QModelIndex - private constructor?:

    Except it cant store shared_ptr ?

    Because that's an object, not a pointer. It has additional data it holds, beside the pointer to your object. In fact it holds at the very least an integer and one pointer in addition to the original pointer to the object.

    Hmm yeap true. Still it has "pointer" written all over it and as far as I can tell its raw 2.0 pointer.

    No it is not. It's a rather expensive mechanism that allows to share ownership to a pointer. And just to be clear, it does not share ownership to the data a pointer references, only to the pointer.

    Perhaps they all should change the naming to call it shared_wrapper/smart_wrapper ?

    Take that with the standards committee. Sharing of pointers is quite the rare case anyway.

    Not sure how much performance that will yeld, I'm looking at milions of objects, if I need to keep making/deleting vectors I will lose cycles on just handling the massive vector list.

    Yeah, and atomic reference counting over an external counter is absolutely free, right?

    Not to mention if I want to delete 500k objects, then I need to filter over the vector to clear objects there too... with shared_ptr/QModelIndex, the second QModelIndex dies and if its the last index then the object would get deleted too.

    If you need to allocate/delete half a million objects the heap manager will eat up your CPU time like it never existed anyway. new/delete ain't free of charge.

    But it stored a pointer to the data.

    You can store a pointer to the data if you wish. QModelIndex will not take ownership, however, so even semantically giving it a shared pointer is wrong. You're trying to force QModelIndex to be owner of some pointer you share with other parts of your program. You're fighting with the model-view framework. I repeat, it is wrong and will not work.

    Right now QStandardModelItem/QStandardItem are based on *Raw pointers. So it's all nice. But if a user(me) wants to use QAbstractItemModel & customItem based on shared_ptr<> then I have no way of using QModelIndex to store/retrieve the internalPointer in a correct format that won't break shared_ptr<>.

    Because you made a wrong design choice. You'll just have to live with it. I understand what you want to do, it's not going to happen.

    As far as I can tell shared_ptr are being pushed out there to replace *raw ptrs so that memory leaks are easier to fix and memory is managed better.

    You are wrong. If that were true you'd see everything in Qt passed through a shared pointer. Have you? Of course not, because external reference counting is not "memory management" by itself. Proper memory management requires discipline to declare clearly what object owns what memory, which many people lack or simply refuse to acknowledge. The std::shared_ptr and it's Qt conterpart QSharedPointer are good for one thing and one thing alone - objects that manage their own lifetime, i.e. they are not owned by any other object, thus the reference to them must be shared.

    Why is it so hard to either expose constructor for qmodelIndex or add a way for it to work with shared_ptr?

    Many reasons. One of them is it breaks binary compatibility. Another is that QModelIndex has to be a template (or an abstract) class to be able to do it, which isn't happening because it can't work with the rest of the model/view. And last, but not least, it's neither necessary, nor is it a correct approach.

    All its need is std::shared_ptr<void*>> - but that needs more hassle, or just expose the constructor from private to public? :/

    QModelIndex isn't made to be derived, that's why it has a private constructor.


  • Qt Champions 2019

    @kshegunov said in Subclassing QModelIndex - private constructor?:

    If you need to allocate/delete half a million objects the heap manager will eat up your CPU time like it never existed anyway

    And the whole ref-counting stuff will eat the last cycles when there are some left... :)



  • Hmmmmmmmm Ok. Time to rethink my live decisions :- )

    Thanks so much for info & putting up with my whining.

    Thanks every one! :- )

    Regards
    Dariusz


Log in to reply