Problems with Open-Source Downloads read https://www.qt.io/blog/problem-with-open-source-downloads and https://forum.qt.io/post/638946

std vector, QVector and fields..



  • Hi..

    Will std vector or QVector help improve performance while grouping fields of the same type?

    example:

    //No vector use:
    //header
    class myclass : public QDialog{
    private: 
        QLabel* lblBG {nullptr};
        QLabel* lblTitle {nullptr};
        QLabel* lblComment {nullptr};
        //others QLabels...
    }
    
    myclass::myclass(){
       lblBG = new QLabel(this);
       lblTitle = new QLabel(this);
       lblComment = new QLabel(this);
       //etc...
    }
    
    //----------------------------------------------
    
    
    //Vector use
    //header
    private:
        enum eQLabels : int {
             elblBG = 0, elblTitle, elblComment
        };
        std::vector<QLabel*> vQLabels;
    }
    
    //cpp
    myclass::myclass(){
        for (ushort x {0}; x != 3; ++x) vQLabels.push_back(new QLabel(this));
        vQLabels[elblBG]->setPixmap(QPixmap(":res/images/img.jpg");
        vQLabels[elblBG]->setScaledContent(true);
         
        vQLabels[elblTitle]->setText(QString("A Title");
        //.etc
    }
    

  • Moderators

    @U7Development said:

    Will std vector or QVector help improve performance while grouping fields of the same type?

    Don't ask. Profile. We can guess but you can actually check.

    But I see no reason why it would help. It's gonna take a bit more memory for the vector and will be a bit slower due to extra indirection when referring to the vector elements. In any case this cost is insignificant compared to a cost of constructing a widget so I doubt it matters.

    If you go for a vector don't forget to use reserve before the loop so you don't reallocate unnecessarily on every push_back.


  • Lifetime Qt Champion

    There will be exactly zero difference, and especially for only three labels.
    Since the size is fixed std::array<> would be better but again - it doesn't matter for three elements at all.


  • Moderators

    @Christian-Ehrlicher said:

    There will be exactly zero difference

    That's not true. There's quite a difference: https://godbolt.org/z/GnoKvh
    But yeah, doesn't matter for this scale.


  • Lifetime Qt Champion

    @Chris-Kawa You're right, the compiler can't know this. But with std::array<> it's the same.

    btw: msvc in godbolt is damn slow.



  • well yes, 3 elements was just an example you know a real form could contain 10 or 20...!

    thanks for answering..


  • Lifetime Qt Champion

    Even 10 or 20 doesn't make a difference in speed. It's just to few.



  • @U7Development
    As the others have said: whether you have an array/list of widget pointers to access versus accessing them directly by variable, even if you had 10,000 of them the array access will be truly negligible compared to the time taken to perform whatever operations on them. setPixmap() or setText() will take way longer. Not to mention, if you really have 10,000 widgets on a page that in itself will cause way more time to handle than how your code accesses them.

    Was your question really about QVector versus std::vector? I thought you were asking about the principle of accessing multiple widgets through an array versus through the individual variables for each one explicitly? In which case: when you want to perform an operation on a particular widget access it via its dedicated variable. If you want to perform an operation on a group of them, by all means create an array/list pointing to them, or use dynamic QObject::findChildren<QLabel*>, for convenience.

    In the example you gave, therefore, when you want to do e.g.

    vQLabels[elblBG]->setPixmap(QPixmap(":res/images/img.jpg");
    

    there is no point actively accessing that through an array, you would be better using the specific lblBG variable, if you have that. But again, don't fret if you don't: reading the pixmap from the resource will take way more time than access an array element.

    Overall, in general: give your particular widgets their own dedicated variable, use that where you want to address that widget. Additionally put those variables into an array if you want the convenience of being able to loop through them doing some operation on each one.

    P.S.
    Don't forget, it's not an either-or, you can happily use both. E.g. (typically using member variables):

    label1 = new QLabel;
    label2 = new QLabel;
    label3 = new QLabel;
    ...
    QVector<QLabel*> labels({label1, label2, label3, ...});
    

  • Moderators

    @JonB said:

    even if you had 10,000 of them the array access will be truly negligible

    Now hold on just a sec. Let's not get carried away. 10'000 is definitely NOT negligible. Those are actually the scales that it starts to matter. The ranges we talked about are around a dozen, not tens of thousands.

    @JonB said:

    or use dynamic QObject::findChildren<QLabel*>, for convenience.

    It should be stated in bold that this should be the last resort, not an option you pick lightly for convenience. If you have another option - take it. This is a very slow lookup over unfriendly data set, especially when recursive. Love your CPU.



  • @Chris-Kawa said in std vector, QVector and fields..:

    Now hold on just a sec. Let's not get carried away. 10'000 is definitely NOT negligible

    Sorry, I just don't agree. I totally understand that 10,000 array accesses cost something. My point is: in practice, what are you going to do on those 10K widgets you pull from an array? Call setPixMap()? Call setText()? Display them all? How do those calls compare to the tiny overhead of picking them out of an array?

    or use dynamic QObject::findChildren<QLabel*>, for convenience

    It should be stated in bold that this should be the last resort

    If I have 10K labels, or 100, and I want to visit them all for whatever purpose, if you want to use individual variables for each one, or enumerate each one to put them into an array explicitly at compile-time, that's up to you. I'll happily use QObject::findChildren<> (or walk the widget hierarchy performing as I go).


  • Moderators

    @JonB said:

    in practice, what are you going to do on those 10K widgets you pull from an array?

    First of all we're talking about vectors. Those are different from arrays because there's extra indirection. 10'000 vs 20'000 pointer cache misses is a significant difference.
    Anyway, there's no point arguing over this. I fully agree with what you said earlier - if you have 10'000 widgets to go through there's something else very wrong with your design.

    @JonB said:

    I'll happily use QObject::findChildren<> (or walk the widget hierarchy performing as I go).

    and a cute fluffy kitten will gruesomely die somewhere every time you do that :(



  • @Chris-Kawa
    Just as briefly as I can, because I cannot abide any harm to kittens....

    • In my current project, I have a principal form which has 37 individual QSpinBoxes for individual, distinct, Qt Creator-designed numerics.
    • I am not prepared to subclass QSpinBox for use in the Designer either via Promotion or via Custom Widget. Let's just take that as a given, please.
    • I need to apply some initial changes to all of them, to do with aligning, coloring. delegating & connecting slots.
    • Following the discussion, I can do this in one of 3 ways:
    1. Explicitly call code on each individual ui->spin... variable. Fastest. Lots & lots of lines of code, doesn't notice if I add an extra spinbox.

    2. Explicitly put those pointers into an array/list/vector by referencing each one at compile-time. Doesn't matter which container, differences are below negligible, compared to what is done on each spin box. (I am not saying this would be the case if I were doing a non-UI, time-critical operation.) Reduces lines of code a lot, still doesn't help with maintaining the list if I add an extra one.

    3. Use QObject::findChildren<QSpinBox*> at run-time to change all such spinboxes, which is exactly what I want, and do. Slowest. Small code, no worries about maintaining a changing list.

    The really important thing about solution #3 is that no kittens, fluffy or otherwise, are harmed in the course of running my application. I would guess the overhead is in milliseconds. Certainly way faster than my eyes can look at the screen or my hands can try to interact with the application. Because that's what humans & computer UIs are like.

    I say this hopefully not to fight with you but because it may relate the situation the OP is asking about.


  • Moderators

    @JonB said:

    I would guess the overhead is in milliseconds

    I work in game dev, where we have 16ms (or 8, depending on an FPS target) to do friggin' everything, so with a statement like that you wouldn't get very popular here :) Not every field has those restrictions of course, but just because you don't have to doesn't mean you shouldn't self-impose those restrictions on yourself even in a more relaxed environment.

    My point is that it's not about what you or the user can see or touch. We're waaaay past that perception point in simple uis. For all a user cares you can use a QMap with QString keys and tripple pointer indirection and no one would be able to tell (that's kinda what findChildren does actually + some casts and branches). But the CPU does the work none the less. It spins those cycles, it takes that electricity, it eats that battery away, it uses up that cache causing evictions to other processes and causing them to use just a little bit more resources. It makes everything else on the system just a little bit more sluggish every time. Given that a random PC is running dozens or hundreds of processes and threads at any given time if everyone coded like this we would be in a very bad place. I hate that every little update and every little app installed makes my PC just a tiny bit slower. It amounts. Nothing runs in isolation.

    no kittens, fluffy or otherwise, are harmed in the course of running my application

    that you know of, but if what you're saying is true... they die man, they die ;)

    I say this hopefully not to fight with you but because it may relate the situation the OP is asking about.

    I hope what I'm saying doesn't come across as fighting. All good here. Just trying to raise awareness of those things because with the rise of the various VMs and interpreted languages performance and battery life are getting destroyed across the board the last few years and it just kills me (along with the kittens) to witness it. I just can't stand that "it doesn't matter, hardware will pick up the slack" programming culture that's on the rise. Don't want to be a silent bystander so I'm bitchn' a bit.


  • Moderators

    @JonB said in std vector, QVector and fields..:

    I need to apply some initial changes to all of them, to do with aligning, coloring. delegating & connecting slots.

    You know, if all those operations are constexpr-able you could do them during compile time!
    Ha dreams 😥



  • @J-Hilk
    Not sure what you mean. Even if they are, the question we are debating is: how do you apply them across 47 design-time (non-subclassed) separate QSpinBoxes? And maintain for future ones which might be added? I'm not prepared to write it against 47 member variables, if I put them into a list/array/vector I have to write/maintain that which equally I don't want to do, so leaves me with QObject::findChildren<QCheckBox *> as the easiest way to implement. Which @Chris-Kawa has informed me will kill my beloved pussy cat, so I feel terrible :(


  • Moderators

    @JonB
    you said

    I need to apply some initial changes to all of them

    which means, you know (theoretically) during compile time what your values should be.

    Now, if all your functions on QCheckBox were constexpr and find children would be as well, you could create a small constexpr function of your own, that finds all QCheckBox and sets the initial values and call that somewhere early on. The compiler would evaluate those calls during compile time and set the initial values accordingly without runtime overhead.


    no kittens required to die, in fact you would have more time, due to longer compile times, to pet them



  • @J-Hilk said in std vector, QVector and fields..:

    you could create a small constexpr function of your own, that finds all QCheckBox

    Not that I can imagine doing this, but could you give an example of how I would do this, at compile-time? Or is that based on a hypothetical "if all your functions on QCheckBox were constexpr and find children would be as well"? I don't follow how you would get a list at compile-time of all QCheckBoxes I have created in Designer (without my having to type that into the source code manually)?


  • Moderators

    @JonB it is hypothetical, because I'm pretty sure setupUi is not constexpr

    but as example, take this compiletime calculation of fibonacci

    constexpr int64_t fibonacci(const int64_t  n)
    {
        return n < 1 ? -1 :
            (n == 1 || n == 2 ? 1 : fibonacci(n - 1) + fibonacci(n - 2));
    }
    
    int main (int argc, char *argv[])
    {
        constexpr auto evaled = fibonacci(25);
            return evaled;
    }
    

    actually had to modify the example to force the compiletime evaluation , a little bit finicky the whole system (still)



  • @J-Hilk
    OK, yes, I know about turning the C++ compiler into an interpreter with constexpr :) But that fibonacci function is self-contained. Compiler is not going to be able to execute anything like constexpr QObject::findChildren<QCheckBox *>, it's runtime-only.

    Purely BTW. I'm not a great programmer (nor mathematician), so while I develop my code I have a go at:

    constexpr int64_t fibonacci(const int64_t  n)
    {
        int64_t result = 0;
        while (n > 0)
            result += n;
        return result;
    }
    

    Now I compile my code. Does the compilation simply hang??


  • Lifetime Qt Champion

    @JonB said in std vector, QVector and fields..:

    Now I compile my code. Does the compilation simply hang??

    No, because you're not calling it :-)
    And it would not hang if you would call it with any number as parameter. It could probably slow down compilation if you would pass a huge number :-)



  • @jsulm
    Oh yes I am! In @J-Hilk's code (at least originally) his main() calls fibonacci(10), so assume that, and then tell me what happens while I sit waiting for the compilation to finish?

    And it would not hang if you would call it with any number as parameter. It could probably slow down compilation if you would pass a huge number :-)

    I think you should look at the code again... :)


  • Lifetime Qt Champion

    @JonB OK, I see n > 0. You should try :-)


  • Moderators

    @JonB Add at least a function call to your calculation, then you get an stack overflow(eventually)



  • @jsulm

    You should try :-)

    I'm terrified of seizing up my Linux VM :) It already does that if I accidentally debug from Creator when inside a QComboBox clicked slot, and I have to hard-switch-off the whole VM... :(


  • Moderators

    @JonB

    main.cpp:158:18: error: expression is not an integral constant expression
    main.cpp:152:13: note: constexpr evaluation hit maximum step limit; possible infinite loop?
    main.cpp:158:18: note: in call to 'fibonacci(25)'
    

    smart things these compilers



  • @J-Hilk said in std vector, QVector and fields..:

    @JonB Add at least a function call to your calculation, then you get an stack overflow(eventually)

    But I don't want a stackoverflow to terminate! I want to know whether the compiler sits there forever! Which is why I wrote as I did.

    OK, I'm off to try....



  • @J-Hilk said in std vector, QVector and fields..:

    note: constexpr evaluation hit maximum step limit; possible infinite loop?

    Ah ha! So..... this C++ constexpr has what "maximum step limit`? Where is that in the spec? :)


  • Moderators

    @JonB up to you with the compiler option -fconstexpr-steps



  • @J-Hilk
    Wow! They think of everything! I wonder if that would accept -fconstexpr-steps fibonacci(25) ;-)

    OK, enough now, thanks!


Log in to reply