Results 1 to 18 of 18

Thread: Nested QHash in range for loop

Hybrid View

Previous Post Previous Post   Next Post Next Post
  1. #1
    Join Date
    Nov 2015
    Posts
    41
    Thanks
    5
    Thanked 3 Times in 3 Posts
    Qt products
    Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Nested QHash in range for loop

    Thanks yeye_olive
    Can you look on my implementation? I tested this code and think that it works fine.

    Qt Code:
    1. class Container
    2. {
    3. public:
    4. Container();
    5.  
    6. void setData(const Data &data);
    7.  
    8.  
    9. using value_type = Data;
    10. using inner_range = QHash<QString, value_type>;
    11. using outer_range = QHash<QString, inner_range>;
    12.  
    13. class iterator : std::iterator_traits<inner_range::iterator>
    14. {
    15. public:
    16. using iterator_category = std::forward_iterator_tag;
    17.  
    18. iterator(outer_range::iterator const & outer_iterator,
    19. outer_range::iterator const & outer_end)
    20. : outer_iterator(outer_iterator), outer_end(outer_end)
    21. {
    22. update();
    23. }
    24.  
    25. iterator & operator++()
    26. {
    27. ++inner_iterator;
    28. if(inner_iterator == inner_end)
    29. {
    30. ++outer_iterator;
    31. update();
    32. }
    33. return *this;
    34. }
    35.  
    36. value_type operator*() const
    37. {
    38. return *inner_iterator;
    39. }
    40.  
    41. bool operator==(iterator const & rhs) const
    42. {
    43. bool lhs_end = outer_iterator == outer_end;
    44. bool rhs_end = rhs.outer_iterator == rhs.outer_end;
    45. if(lhs_end && rhs_end)
    46. return true;
    47. if(lhs_end != rhs_end)
    48. return false;
    49. return outer_iterator == rhs.outer_iterator
    50. && inner_iterator == rhs.inner_iterator;
    51. }
    52.  
    53. bool operator!=(iterator const &other) const
    54. {
    55. return !(*this == other);
    56. }
    57.  
    58.  
    59. private:
    60. outer_range::iterator outer_iterator, outer_end;
    61. inner_range::iterator inner_iterator, inner_end;
    62.  
    63. void update()
    64. {
    65. while(outer_iterator != outer_end)
    66. {
    67. inner_iterator = (*outer_iterator).begin();
    68. inner_end = (*outer_iterator).end();
    69. if(inner_iterator == inner_end)
    70. ++outer_iterator;
    71. else
    72. break;
    73. }
    74. }
    75. };
    76.  
    77.  
    78. Container::iterator begin();
    79. Container::iterator end();
    80.  
    81. private:
    82. QHash<QString, QHash<QString, Data>> d;
    83. };
    To copy to clipboard, switch view to plain text mode 

    anda_skoa
    And be aware that using a ranged for on a Qt container will require the Qt container to do a deep copy if it is used in more than one variable at the time of iteration.
    What exactly you mean?
    When I use this container like that:

    Qt Code:
    1. for( const Data &x : d )
    2. qDebug()<< x.scope << "::" << x.name << ", " << x.value;
    To copy to clipboard, switch view to plain text mode 

    then it should not create a copy of each elemenet.

    And importan question, whether i should stay with QHash whether I can obtain better performance using QMap?

    Especially when keys are type of QString which can have between one to over a dozen characters and when each Container should have average 1 <= x <= 30 properties as Data.
    Last edited by Scope; 4th December 2015 at 20:15.

  2. #2
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Nested QHash in range for loop

    Quote Originally Posted by Scope View Post
    What exactly you mean?
    When I use this container like that:

    Qt Code:
    1. for( const Data &x : d )
    2. qDebug()<< x.scope << "::" << x.name << ", " << x.value;
    To copy to clipboard, switch view to plain text mode 

    then it should not create a copy of each elemenet.
    Qt containers are implicitly shared, they use reference counting to avoid deep copying on assignment/copying.

    Qt Code:
    1. QHash<QString, QString> h1;
    2. h1.insert("a", "1");
    3. h1.insert("b", "2");
    4.  
    5. QHash<QString, QString> h2 = h1; // h2 and h1 shared the same data. reference count is 2
    6.  
    7. for (const QString &value, h1) { // h1 detaches, creates a deep copy, h2 and h1 now point to different data, each having a ref count of 1
    8. }
    To copy to clipboard, switch view to plain text mode 
    Detaching is triggered by calling non-const methods. begin()/end() are non-const unless the instance they are called on is const.

    So make sure that either
    - the container is not having a ref count > 1
    - the container is constant
    or use foreach()

    Cheers,
    _

  3. #3
    Join Date
    Nov 2015
    Posts
    41
    Thanks
    5
    Thanked 3 Times in 3 Posts
    Qt products
    Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Nested QHash in range for loop

    Ok, I think that this should not be a problem - if Qt containers inside range for loop create a deep copy then my class can have a similar behavior.

    And importan question, whether i should stay with QHash whether I can obtain better performance using QMap?

    Especially when keys are type of QString which can have between one to over a dozen characters and when each Container should have average 1 <= x <= 30 properties as Data.
    Thanks,

  4. #4
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Nested QHash in range for loop

    Quote Originally Posted by Scope View Post
    Ok, I think that this should not be a problem - if Qt containers inside range for loop create a deep copy then my class can have a similar behavior.
    Well, usually one doesn't use ranged-for with a Qt container unless it is ensured that there won't be the penalty of the deep copy.

    Cheers,
    _

  5. The following user says thank you to anda_skoa for this useful post:

    Scope (6th December 2015)

  6. #5
    Join Date
    Nov 2015
    Posts
    41
    Thanks
    5
    Thanked 3 Times in 3 Posts
    Qt products
    Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Nested QHash in range for loop

    I found on Qt blog that this problem can be solve using simple template

    Qt Code:
    1. template<class T> const T &const_(const T &t) { return t; }
    2. for(auto it : const_(vector)) { ... }
    To copy to clipboard, switch view to plain text mode 

    Thanks and regards

  7. #6
    Join Date
    Oct 2009
    Posts
    483
    Thanked 97 Times in 94 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Nested QHash in range for loop

    Quote Originally Posted by Scope View Post
    Can you look on my implementation? I tested this code and think that it works fine.
    Here are my comments on your implementation:

    Your iterator advertizes itself a forward iterator, therefore it should provide default construction and post-incrementation.

    Line 36: the return type should ve value_type &, not value_type (see more about this below).

    Operator ==: your implementation works perfectly, but you could make it faster thanks to the precondition that *this and rhs are on the same container. For instance:
    Qt Code:
    1. return outer_iterator == rhs.outer_iterator && (outer_iterator == outer_end || inner_iterator == rhs.inner_iterator);
    To copy to clipboard, switch view to plain text mode 
    About the wrong return type at line 36: you chose to implement an iterator (as opposed to a const_iterator), which is expected to let the user modify the elements of the container; that is why operator*() should return a non-const reference to the element. Naturally you should also add a comment warning the user against modifying Data::scope and Data::name through this iterator, as this would break the invariant of your Container. (std::map and std::unordered_map have exactly the same problem.)

    You should also provide a const_iterator in addition to the iterator, especially if all the iterations you care about are read-only (and the fact that your current operator*() returns a copy of the element is a clear indication that it is the case). Not only will you enjoy the added safety from the type system, but you will also gain a performance advantage since the underlying QHash::const_iterators will not force the QHash to perform a deep copy in case of implicit sharing.

    Quote Originally Posted by Scope View Post
    And importan question, whether i should stay with QHash whether I can obtain better performance using QMap?

    Especially when keys are type of QString which can have between one to over a dozen characters and when each Container should have average 1 <= x <= 30 properties as Data.
    You will most likely obtain better performance with a QHash than with a QMap. The main advantage of QMap over QHash is that the collection is sorted. Unless you care about that, you should stick with QHash.

    Quote Originally Posted by Scope View Post
    I found on Qt blog that this problem can be solve using simple template

    Qt Code:
    1. template<class T> const T &const_(const T &t) { return t; }
    2. for(auto it : const_(vector)) { ... }
    To copy to clipboard, switch view to plain text mode 
    For that to work, you must provide a const_iterator and const begin() and end() methods. Also, your syntax is friendlier than the static_cast beast I wrote in a previous post, but requires the additional helper definition of const_; I still cannot understand why the standard library does not provide it.

Similar Threads

  1. Loop or Nested Iterator
    By enricong in forum Qt Programming
    Replies: 3
    Last Post: 28th September 2011, 06:06
  2. Replies: 4
    Last Post: 6th August 2011, 01:40
  3. Main loop thread loop communication
    By mcsahin in forum Qt Programming
    Replies: 7
    Last Post: 25th January 2011, 16:31
  4. Replies: 1
    Last Post: 10th February 2009, 09:42
  5. Can QHash::capacity() be smaller than QHash::size()?!?
    By iw2nhl in forum Qt Programming
    Replies: 2
    Last Post: 24th August 2007, 01:17

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Qt is a trademark of The Qt Company.