问题
I have a polymorphic tree of C++ types that I need to work with from QML. Memory usage and performance are key here, so I wonder which approach would be more efficient:
Q_GADGET
- without a doubt the easier and faster way to do it. I can directly use properties (without notifications so no bindings either) and slots to access each object's members. It relies on meta data generation and some kind of object identification in the qtquick runtime.Use an global accessor object for accessing everything, getting or setting object properties, invoking functions and so on. This is definitely the slower and more verbose solution.
I have previously tried with QObject
derived types registered as QML types, but memory usage was horrific. I had huge overhead from QObject
alone - about 140 bytes overhead for the base 16 byte data set, and instantiating the objects in QML made that even worse, soaring the overhead to around 2000 bytes. Which is unacceptable considering the high object count I am dealing with.
So now I am going the long way, and scrapping the previous design, and wonder what would be the most efficient implementation to take. Also, whether the meta stuff associated with Q_GADGET
will work out nicely in a polymorphic scenario.
回答1:
So I decided to give both approaches a test run and make a comparison.
My efforts were cut short, thankfully in their infancy, by the usual obligatory Qt limitation - turns out Q_GADGET
doesn't work with pointers, neither properties nor functions are available when working with them on pointer basis.
Only instances are supported for member access, therefore that option is not applicable in a polymorphic scenario. Manual accessor object it is!
Update:
There is a workaround for this, but it involves extra work. Implementing the PIMPL idiom you can have the object instance implementing the properties simply being a pointer to the actual implementation, making all the copying around applicable and efficient.
I ended up not using that approach however, mainly due to the fact it still did not support notifications, and the "3rd party" notification implementation turned out to be too inefficient. Instead I went for a QObject
based "proxy" or "accessor" for every object, referenced by a QML element. The proxy is created on demand, and is reference counted, so it only exists whenever an "object -> qml" bridge is needed, which is always only for a very small subset of all objects. The proxy is tightly coupled with the object to avoid penalties of looking it up, while the GUI itself is still abstracted away.
The real world advantage of that implementation compared with the old, QML object based is impressive. From running out of memory on a 32bit build around 300k objects, it is now capable of handling around 500M, a 1666x fold improvement.
来源:https://stackoverflow.com/questions/42843942/q-gadget-vs-an-accessor-object-for-manipulating-a-polymorphic-tree-of-c-object