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. Using STL Algorithms with Qt Containers
QtWS25 Last Chance

Using STL Algorithms with Qt Containers

Scheduled Pinned Locked Moved General and Desktop
12 Posts 6 Posters 4.0k 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.
  • I Offline
    I Offline
    isaacEnrique
    wrote on last edited by
    #1

    I wonder if it is better to travel the Qt containers (QList, QVector, etc) using the STL generic algorithm 'for_each ()' or use a simple 'for()' and indexing with the operator '[]' or the function 'at()'. Overall I wonder whether is convenient to use the STL generic algorithms as 'find_if ()', 'find()', 'count()', etc, with the Qt containers.

    Thanks in advance for any clarification.

    Isaac Pérez
    Programming is understanding.

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

      Hi,

      For Qt 5, it's recommended to use the STL algorithms when possible see the "QtAlgorithms":http://doc.qt.io/qt-5/qtalgorithms.html#qt-and-the-stl-algorithms documentation

      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
      0
      • I Offline
        I Offline
        isaacEnrique
        wrote on last edited by
        #3

        Thanks very good information.

        But then... use the STL algorithms as 'for_each()' is more efficient than traverse a Qt container with a simple loop 'for()'?... So I understand the answer is YES (or am I wrong?)

        Isaac Pérez
        Programming is understanding.

        1 Reply Last reply
        0
        • C Offline
          C Offline
          ckakman
          wrote on last edited by
          #4

          The page at the link SGaist provided recommends to use the STL algorithms instead of the equivalent algorithms in QtAlgorithms.

          Qt's containers are compatible with STL algorithms so you wouldn't have any issues there.

          Using std::for_each() instead of a plain for loop not necessarily results in a more or less efficient code. Experienced C++ developers would claim that using STL algorithms makes your code more succinct, especially when used with lambdas, more readable, makes your intent clearer. STL is a well implemented library by all major compiler vendors, so performance shouldn't be the main concern when using STL.

          If you are using a compiler that supports C++11, using STL algorithms is much more convenient than before.

          1 Reply Last reply
          0
          • JKSHJ Offline
            JKSHJ Offline
            JKSH
            Moderators
            wrote on last edited by
            #5

            [quote author="IsaacEnrique" date="1421090338"]use the STL algorithms as 'for_each()' is more efficient than traverse a Qt container with a simple loop 'for()'?... So I understand the answer is YES (or am I wrong?)[/quote]There is no clear answer. (The answer might be different, depending on which compiler you use.)

            You should test it yourself to find the answer. Write one program that uses for_each(), then write another program that uses for() with indexing. Then, compare the performance of the two programs.

            Also, which is more important to you: High performance, or simple code?

            Qt Doc Search for browsers: forum.qt.io/topic/35616/web-browser-extension-for-improved-doc-searches

            1 Reply Last reply
            0
            • A Offline
              A Offline
              andre
              wrote on last edited by
              #6

              [quote author="SGaist" date="1421084932"]Hi,

              For Qt 5, it's recommended to use the STL algorithms when possible see the "QtAlgorithms":http://doc.qt.io/qt-5/qtalgorithms.html#qt-and-the-stl-algorithms documentation[/quote]

              Yes, though I do find that a pitty. The syntax for the Qt variants was so much nicer... It's just plain annoying to have to explicitly provide the begin and end iterators when you want to apply an algorithm on a complete container (as you most often will want).

              [quote author="IsaacEnrique" date="1421090338"]
              But then... use the STL algorithms as 'for_each()' is more efficient than traverse a Qt container with a simple loop 'for()'?... So I understand the answer is YES (or am I wrong?)[/quote]
              Why not go for a range-based for loop directly?

              @
              for(auto myItem : myContainer) {
              //do stuff with myItem
              }
              @
              or, if you don't want to modify your item:
              @
              for (const auto& myItem : myContainer) {
              //read from your item
              }
              @

              1 Reply Last reply
              0
              • I Offline
                I Offline
                isaacEnrique
                wrote on last edited by
                #7

                Thank you all for your suggestions, all presented well-founded arguments.

                Regarding efficiency I really had not considered that the answer could be compiler dependent (as JKSH says).

                However, I suppose that in any case the difference in performance of the two options should be minimal?

                Isaac Pérez
                Programming is understanding.

                1 Reply Last reply
                0
                • I Offline
                  I Offline
                  ivan
                  wrote on last edited by
                  #8

                  Because of Qt's use of CoW (copy-on-write), the range-for can be slow since it calls begin() which detaches the shared state even if you don't modify the content. Q_FOREACH(...) could prove to be a faster solution (was told about this, but I haven't checked).

                  When using STL algorithms, if you are not changing anything, you can pass cbegin and cend and you will not get any CoW-related performance penalties.

                  If you want the 'pretty' syntax of not passing iterrator pairs, check out boost algorithms, boost.range library and, eventually, features of c++17.

                  Ivan Čukić | ivan.cukic(at)kde.org | KDE e.V.
                  Qt Ambassador (from the old Nokia days)

                  1 Reply Last reply
                  0
                  • A Offline
                    A Offline
                    andre
                    wrote on last edited by
                    #9

                    Wouldn't they call cbegin and cend (C++/14)?
                    But it is indeed something to take into account... Thanks for that note!

                    1 Reply Last reply
                    0
                    • I Offline
                      I Offline
                      isaacEnrique
                      wrote on last edited by
                      #10

                      Excuse my ignorance, but:

                      What if I traverse a Qt Container (eg QList) using non-constant iterators 'begin()' and 'end()'?

                      Isaac Pérez
                      Programming is understanding.

                      1 Reply Last reply
                      0
                      • I Offline
                        I Offline
                        ivan
                        wrote on last edited by
                        #11

                        [quote author="Andre" date="1421161617"]Wouldn't they call cbegin and cend (C++/14)?
                        But it is indeed something to take into account... Thanks for that note![/quote]

                        It should not from what I can see from the C++14 final draft.

                        @
                        for (decl: expr) statement
                        @

                        expands to:

                        @
                        {
                        auto && __range = range-init;
                        for ( auto __begin = begin-expr, __end = end-expr; __begin != __end;
                        ++__begin ) {
                        decl = *__begin;
                        statement
                        }
                        }
                        @

                        where init can be:

                        • __range for arrays
                        • __range.begin() when .begin() exists
                        • begin(__range) otherwise

                        I guess that the reasoning behind this is that compiler does not want to check whether the 'statement' part alters anything or not. I suppose they had a reason not to base the choice between begin and cbegin on whether it is a for(... : ...) or for(const ... : ...).

                        Some people are proposing a method like make_const which would just cast T to a const T on which begin and cbegin would return the same thing - and this would remove the CoW issue in the case of Qt.

                        [quote author="IsaacEnrique" date="1421255690"]Excuse my ignorance, but:

                        What if I traverse a Qt Container (eg QList) using non-constant iterators 'begin()' and 'end()'?[/quote]

                        You'll get a copy as soon as you call .begin() (if the list is implicitly shared ofcourse).

                        Ivan Čukić | ivan.cukic(at)kde.org | KDE e.V.
                        Qt Ambassador (from the old Nokia days)

                        1 Reply Last reply
                        0
                        • I Offline
                          I Offline
                          isaacEnrique
                          wrote on last edited by
                          #12

                          bq. Ivan Čukić wrote:
                          You’ll get a copy as soon as you call .begin() (if the list is implicitly shared ofcourse).

                          Are you referring to a copy of the entire list?

                          Does using .cbegin() and .cend() can avoid it?, e.g doing the following:

                          @
                          QList< MyCustomObject > l;

                          /* ... */

                          QList< MyCustomObject >::const_iterator it;

                          std::for_each(it = l.cbegin(); it != l.cend(); /* ... */)
                          @

                          No will make any copy?... Right?

                          And in case published by Andre:

                          @
                          for (const auto& myItem : myContainer)
                          {
                          //read from your item
                          }
                          @

                          An implicit deep copy is not made here... or am I wrong?

                          Isaac Pérez
                          Programming is understanding.

                          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