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. QHash with QObject based value type produces unexpected results
QtWS25 Last Chance

QHash with QObject based value type produces unexpected results

Scheduled Pinned Locked Moved Solved General and Desktop
qhashqobjectiterator
15 Posts 3 Posters 1.2k Views
  • 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.
  • V Offline
    V Offline
    VRonin
    wrote on 16 Sept 2024, 15:11 last edited by
    #4

    What gets hashed is the key, not the value. The hash you are reading are of QWidget*

    "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
    ~Napoleon Bonaparte

    On a crusade to banish setIndexWidget() from the holy land of Qt

    P 1 Reply Last reply 16 Sept 2024, 15:17
    2
    • V VRonin
      16 Sept 2024, 15:11

      What gets hashed is the key, not the value. The hash you are reading are of QWidget*

      P Offline
      P Offline
      Pl45m4
      wrote on 16 Sept 2024, 15:17 last edited by Pl45m4
      #5

      @VRonin

      That explains why changing the qHash function doesn't solve it. :D
      So how to deal with it?

      I mean, if MyData entries are not hashed, why I'm not able to compare their id?


      If debugging is the process of removing software bugs, then programming must be the process of putting them in.

      ~E. W. Dijkstra

      1 Reply Last reply
      0
      • V Offline
        V Offline
        VRonin
        wrote on 16 Sept 2024, 15:23 last edited by
        #6

        It depends on what you are trying to do. From what you describe it looks like what you actually want is a QHash<int,MyData*> where the key is my_daya.id().

        What is not clear from above is how you are actually using the current key i.e. the QWidget*

        "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
        ~Napoleon Bonaparte

        On a crusade to banish setIndexWidget() from the holy land of Qt

        P 1 Reply Last reply 16 Sept 2024, 15:36
        0
        • V VRonin
          16 Sept 2024, 15:23

          It depends on what you are trying to do. From what you describe it looks like what you actually want is a QHash<int,MyData*> where the key is my_daya.id().

          What is not clear from above is how you are actually using the current key i.e. the QWidget*

          P Offline
          P Offline
          Pl45m4
          wrote on 16 Sept 2024, 15:36 last edited by Pl45m4
          #7

          @VRonin said in QHash with QObject based value type produces unexpected results:

          QHash<int,MyData*>

          Why would you need this, when int ID is a member in MyData?

          Actually I took the idea from the implementation of QButtonGroup.
          QAbstractButton - widgets are mapped to their groupID the same way I'm trying to do... with that one difference:
          As used in my "working" cases, they are mapped to the plain int ID's and not to a struct/class which contains the ID.
          Like QHash<QAbstractButton *, int>, where int is the groupID.

          Where I thought of:
          QHash<QWidget *, MyData.id() > (makes no sense written like this, but you see what I'm trying)

          I (think I) need to store a pointer to the complete class MyData, because I want to let MyData emit signals depending on the look-up results and not only store the ID.

          Otherwise I would need 2-3 more maps/hashes?!
          Map Widget to ID, map ID to another class (MyData), then do something and map it to my initial Widget...
          That doesn't sound right/like a good design, though.


          If debugging is the process of removing software bugs, then programming must be the process of putting them in.

          ~E. W. Dijkstra

          V 1 Reply Last reply 16 Sept 2024, 15:55
          0
          • P Pl45m4
            16 Sept 2024, 15:36

            @VRonin said in QHash with QObject based value type produces unexpected results:

            QHash<int,MyData*>

            Why would you need this, when int ID is a member in MyData?

            Actually I took the idea from the implementation of QButtonGroup.
            QAbstractButton - widgets are mapped to their groupID the same way I'm trying to do... with that one difference:
            As used in my "working" cases, they are mapped to the plain int ID's and not to a struct/class which contains the ID.
            Like QHash<QAbstractButton *, int>, where int is the groupID.

            Where I thought of:
            QHash<QWidget *, MyData.id() > (makes no sense written like this, but you see what I'm trying)

            I (think I) need to store a pointer to the complete class MyData, because I want to let MyData emit signals depending on the look-up results and not only store the ID.

            Otherwise I would need 2-3 more maps/hashes?!
            Map Widget to ID, map ID to another class (MyData), then do something and map it to my initial Widget...
            That doesn't sound right/like a good design, though.

            V Offline
            V Offline
            VRonin
            wrote on 16 Sept 2024, 15:55 last edited by
            #8

            @Pl45m4 said in QHash with QObject based value type produces unexpected results:

            because I want to let MyData emit signals depending on the look-up results

            If your lookup is based on QWidget * then you don't need to hash MyData because that's not what you are looking up.

            If you want a hash that can search for either QWidget* or MyData* then you need a bidirectional container like KBiHash (https://invent.kde.org/frameworks/kitemmodels/-/blob/master/src/core/kbihash_p.h#L543)

            "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
            ~Napoleon Bonaparte

            On a crusade to banish setIndexWidget() from the holy land of Qt

            P 1 Reply Last reply 17 Sept 2024, 12:35
            0
            • V VRonin
              16 Sept 2024, 15:55

              @Pl45m4 said in QHash with QObject based value type produces unexpected results:

              because I want to let MyData emit signals depending on the look-up results

              If your lookup is based on QWidget * then you don't need to hash MyData because that's not what you are looking up.

              If you want a hash that can search for either QWidget* or MyData* then you need a bidirectional container like KBiHash (https://invent.kde.org/frameworks/kitemmodels/-/blob/master/src/core/kbihash_p.h#L543)

              P Offline
              P Offline
              Pl45m4
              wrote on 17 Sept 2024, 12:35 last edited by Pl45m4 23 days from now
              #9

              @VRonin said in QHash with QObject based value type produces unexpected results:

              If your lookup is based on QWidget * then you don't need to hash MyData because that's not what you are looking up

              So why are my results for <QWidget *, MyData*> and <QWidget *, int> different then?
              In both cases I compare the ID (int).
              First one via MyData::id(), second one by reading the int value from the hash directly.

              From my understanding...
              If in both cases the only the QWidget is hashed, then there should be no problem with the hash itself... and my logic, what I'm doing afterwards (see testFunction[Data|Int]) is completely identical.

              Am I still doing something wrong there?

              Has anyone tried my sample code?

              Edit:

              While writing this, I think I know...
              std::max_element in both cases iterates the hash and seems to compare the value of all keys, returning the largest/highest value...
              That means, even if I use it.value().id() to get the actual ID from MyData.... The object I'm calling this function on, is not the one with the highest ID. If I'm not mistaken, std::max_element compares the pointers to MyData and returns the highest value (I suspect the highest address to win)... since I don't have a specific operator < implemented, which tells that my intention is to compare MyData * by using MyData::id().

              Will try to add a new set of operators and check the output again...

              Edit_2:

              Moving to C++20 so that std::max_element uses std::less might be also worth a try. Still need to implement comparison operator. Otherwise they are ordered by:

              • https://en.cppreference.com/w/cpp/language/operator_comparison#Pointer_total_order

              If debugging is the process of removing software bugs, then programming must be the process of putting them in.

              ~E. W. Dijkstra

              V P 2 Replies Last reply 17 Sept 2024, 14:53
              0
              • P Pl45m4
                17 Sept 2024, 12:35

                @VRonin said in QHash with QObject based value type produces unexpected results:

                If your lookup is based on QWidget * then you don't need to hash MyData because that's not what you are looking up

                So why are my results for <QWidget *, MyData*> and <QWidget *, int> different then?
                In both cases I compare the ID (int).
                First one via MyData::id(), second one by reading the int value from the hash directly.

                From my understanding...
                If in both cases the only the QWidget is hashed, then there should be no problem with the hash itself... and my logic, what I'm doing afterwards (see testFunction[Data|Int]) is completely identical.

                Am I still doing something wrong there?

                Has anyone tried my sample code?

                Edit:

                While writing this, I think I know...
                std::max_element in both cases iterates the hash and seems to compare the value of all keys, returning the largest/highest value...
                That means, even if I use it.value().id() to get the actual ID from MyData.... The object I'm calling this function on, is not the one with the highest ID. If I'm not mistaken, std::max_element compares the pointers to MyData and returns the highest value (I suspect the highest address to win)... since I don't have a specific operator < implemented, which tells that my intention is to compare MyData * by using MyData::id().

                Will try to add a new set of operators and check the output again...

                Edit_2:

                Moving to C++20 so that std::max_element uses std::less might be also worth a try. Still need to implement comparison operator. Otherwise they are ordered by:

                • https://en.cppreference.com/w/cpp/language/operator_comparison#Pointer_total_order
                V Offline
                V Offline
                VRonin
                wrote on 17 Sept 2024, 14:53 last edited by VRonin
                #10

                @Pl45m4 said in QHash with QObject based value type produces unexpected results:

                std::max_element in both cases iterates the hash and seems to compare the value of all keys

                Nope, it uses QHash<QWidget *, MyData *>::iterator::operator*() so it compares all values not all keys

                @Pl45m4 said in QHash with QObject based value type produces unexpected results:

                std::max_element compares the pointers to MyData and returns the highest value (I suspect the highest address to win)... since I don't have a specific operator < implemented, which tells that my intention is to compare MyData * by using MyData::id().

                Bingo! that's your problem but you can just use the 3rd argument of std::max_element, no need for crazy stuff: QHash<QWidget *, MyData *>::iterator it = std::max_element(dataMapping.begin(), dataMapping.end(), [](MyData *a, MyData *b) -> bool {return a->id() < b->id();});

                "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
                ~Napoleon Bonaparte

                On a crusade to banish setIndexWidget() from the holy land of Qt

                1 Reply Last reply
                1
                • P Pl45m4
                  17 Sept 2024, 12:35

                  @VRonin said in QHash with QObject based value type produces unexpected results:

                  If your lookup is based on QWidget * then you don't need to hash MyData because that's not what you are looking up

                  So why are my results for <QWidget *, MyData*> and <QWidget *, int> different then?
                  In both cases I compare the ID (int).
                  First one via MyData::id(), second one by reading the int value from the hash directly.

                  From my understanding...
                  If in both cases the only the QWidget is hashed, then there should be no problem with the hash itself... and my logic, what I'm doing afterwards (see testFunction[Data|Int]) is completely identical.

                  Am I still doing something wrong there?

                  Has anyone tried my sample code?

                  Edit:

                  While writing this, I think I know...
                  std::max_element in both cases iterates the hash and seems to compare the value of all keys, returning the largest/highest value...
                  That means, even if I use it.value().id() to get the actual ID from MyData.... The object I'm calling this function on, is not the one with the highest ID. If I'm not mistaken, std::max_element compares the pointers to MyData and returns the highest value (I suspect the highest address to win)... since I don't have a specific operator < implemented, which tells that my intention is to compare MyData * by using MyData::id().

                  Will try to add a new set of operators and check the output again...

                  Edit_2:

                  Moving to C++20 so that std::max_element uses std::less might be also worth a try. Still need to implement comparison operator. Otherwise they are ordered by:

                  • https://en.cppreference.com/w/cpp/language/operator_comparison#Pointer_total_order
                  P Offline
                  P Offline
                  Pl45m4
                  wrote on 17 Sept 2024, 15:23 last edited by Pl45m4
                  #11

                  @Pl45m4 said in QHash with QObject based value type produces unexpected results:

                  Will try to add a new set of operators and check the output again...

                  Implementing

                  inline bool operator<(MyData *data1, MyData *data2){ return data1->id() < data2->id(); }
                  

                  results in:

                  main.cpp:26:13: Overloaded 'operator<' must have at least one parameter of class or enumeration type

                  So it's not supported by any operator and C++ standard.

                  And because you also cannot store QObject types by value in a container (no copy/assignment c'tor), it's never going to work :(

                  I guess I have to think about my design again esp. how I'm going to map the information together and how to access them :/

                  Maybe I get rid of the QObject inheritance and store plain data "struct", which then would be mappable again...

                  Thanks to anyone who contributed :)

                  Edit:

                  As the discussion was progressed further:
                  This turns out to be one possible solution:

                  @VRonin said in QHash with QObject based value type produces unexpected results:

                  Bingo! that's your problem but you can just use the 3rd argument of std::max_element, no need for crazy stuff: QHash<QWidget *, MyData *>::iterator it = std::max_element(dataMapping.begin(), dataMapping.end(), [](MyData *a, MyData *b) -> bool {return a->id() < b->id();});

                  However, will see if I re-design this whole part of my app or just use it like this... :)


                  If debugging is the process of removing software bugs, then programming must be the process of putting them in.

                  ~E. W. Dijkstra

                  V 1 Reply Last reply 17 Sept 2024, 15:28
                  0
                  • P Pl45m4
                    17 Sept 2024, 15:23

                    @Pl45m4 said in QHash with QObject based value type produces unexpected results:

                    Will try to add a new set of operators and check the output again...

                    Implementing

                    inline bool operator<(MyData *data1, MyData *data2){ return data1->id() < data2->id(); }
                    

                    results in:

                    main.cpp:26:13: Overloaded 'operator<' must have at least one parameter of class or enumeration type

                    So it's not supported by any operator and C++ standard.

                    And because you also cannot store QObject types by value in a container (no copy/assignment c'tor), it's never going to work :(

                    I guess I have to think about my design again esp. how I'm going to map the information together and how to access them :/

                    Maybe I get rid of the QObject inheritance and store plain data "struct", which then would be mappable again...

                    Thanks to anyone who contributed :)

                    Edit:

                    As the discussion was progressed further:
                    This turns out to be one possible solution:

                    @VRonin said in QHash with QObject based value type produces unexpected results:

                    Bingo! that's your problem but you can just use the 3rd argument of std::max_element, no need for crazy stuff: QHash<QWidget *, MyData *>::iterator it = std::max_element(dataMapping.begin(), dataMapping.end(), [](MyData *a, MyData *b) -> bool {return a->id() < b->id();});

                    However, will see if I re-design this whole part of my app or just use it like this... :)

                    V Offline
                    V Offline
                    VRonin
                    wrote on 17 Sept 2024, 15:28 last edited by VRonin
                    #12

                    @Pl45m4 said in QHash with QObject based value type produces unexpected results:

                    So it's not supported by any operator and C++ standard.

                    Yes, overloading operators for built in types (pointers in this case) is explicitly forbidden by the standard. Hence why I use a lambda above. If you are pre-C++11 then you can use functor:

                    class MyDataCompare{
                    public:
                    bool operator()(MyData *data1, MyData *data2) const { return data1->id() < data2->id(); }
                    }
                    

                    "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
                    ~Napoleon Bonaparte

                    On a crusade to banish setIndexWidget() from the holy land of Qt

                    P 1 Reply Last reply 17 Sept 2024, 18:04
                    1
                    • P Pl45m4 has marked this topic as solved on 17 Sept 2024, 15:29
                    • V VRonin
                      17 Sept 2024, 15:28

                      @Pl45m4 said in QHash with QObject based value type produces unexpected results:

                      So it's not supported by any operator and C++ standard.

                      Yes, overloading operators for built in types (pointers in this case) is explicitly forbidden by the standard. Hence why I use a lambda above. If you are pre-C++11 then you can use functor:

                      class MyDataCompare{
                      public:
                      bool operator()(MyData *data1, MyData *data2) const { return data1->id() < data2->id(); }
                      }
                      
                      P Offline
                      P Offline
                      Pl45m4
                      wrote on 17 Sept 2024, 18:04 last edited by
                      #13

                      @VRonin said in QHash with QObject based value type produces unexpected results:

                      If you are pre-C++11 then you can use functor:

                      Pre-C++11?!
                      So C++0X or C++98?!
                      I don't know if I want to use a C++ Standard this old.
                      Doesn't Qt6 need at least C++11 or something to work?

                      I'm still wondering what I could do, now that I know that my initial idea isn't working.


                      If debugging is the process of removing software bugs, then programming must be the process of putting them in.

                      ~E. W. Dijkstra

                      V 1 Reply Last reply 17 Sept 2024, 21:18
                      0
                      • P Pl45m4
                        17 Sept 2024, 18:04

                        @VRonin said in QHash with QObject based value type produces unexpected results:

                        If you are pre-C++11 then you can use functor:

                        Pre-C++11?!
                        So C++0X or C++98?!
                        I don't know if I want to use a C++ Standard this old.
                        Doesn't Qt6 need at least C++11 or something to work?

                        I'm still wondering what I could do, now that I know that my initial idea isn't working.

                        V Offline
                        V Offline
                        VRonin
                        wrote on 17 Sept 2024, 21:18 last edited by
                        #14

                        @Pl45m4 maybe I’m missing something but I did suggest a solution above (passing a lambda as extra argument to max_element) is that not feasible for your code?

                        "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
                        ~Napoleon Bonaparte

                        On a crusade to banish setIndexWidget() from the holy land of Qt

                        P 1 Reply Last reply 18 Sept 2024, 22:10
                        0
                        • V VRonin
                          17 Sept 2024, 21:18

                          @Pl45m4 maybe I’m missing something but I did suggest a solution above (passing a lambda as extra argument to max_element) is that not feasible for your code?

                          P Offline
                          P Offline
                          Pl45m4
                          wrote on 18 Sept 2024, 22:10 last edited by Pl45m4
                          #15

                          @VRonin

                          I misread your reply.
                          Was looking at the functor code and thought, huh, why you need C++11 or below.
                          Missed that you referred with "lambda" to the code sample 1-2 posts earlier.

                          Yes, the lambda, in which I tell std::max_element how to compare, works.
                          I still take this as a chance to re-think what I'm doing and if there is a better way.

                          Thank you :)


                          If debugging is the process of removing software bugs, then programming must be the process of putting them in.

                          ~E. W. Dijkstra

                          1 Reply Last reply
                          0
                          • P Pl45m4 referenced this topic on 6 Jan 2025, 17:05

                          13/15

                          17 Sept 2024, 18:04

                          • Login

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