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 }
-
@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 everypush_back
. -
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. -
@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. -
@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..
-
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()
orsetText()
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
versusstd::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 dynamicQObject::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, ...});
-
@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()
? CallsetText()
? 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). -
@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
QSpinBox
es 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:
-
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. -
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.
-
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.
- In my current project, I have a principal form which has 37 individual
-
@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.
-
@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) separateQSpinBox
es? 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 withQObject::findChildren<QCheckBox *>
as the easiest way to implement. Which @Chris-Kawa has informed me will kill my beloved pussy cat, so I feel terrible :( -
@JonB
you saidI 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
QCheckBox
es I have created in Designer (without my having to type that into the source code manually)? -
@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 withconstexpr
:) But thatfibonacci
function is self-contained. Compiler is not going to be able to execute anything likeconstexpr 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??
-
@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 :-)