Inside the QTableWidget, I'm guessing I'll have ~100 of my custom widgets at most.
In other use cases (i.e. not in the QTableWidget, but in static layouts), I've had up to 4000 of these widgets, with a few hundred being active (i.e. actively refreshing their data from the backend) at the same time, without any serious performance issues, so I know it scales relatively well.
Also, to elaborate on the solution I offered above: cloning the custom widget proved difficult, because it has a lot of properties (I simplified the problem, the "custom widget" is actually a family of different widgets to fit different data), and because copying Qt objects is not trivial (see http://doc.qt.io/qt-5/object.html#identity-vs-value).
What I ended up doing was write a ContainerWidget to go along the GridWidget. The ContainerWidget has a layout with no margins and is used to display another widget through a setContainedWidget() method. I also added a cloneAndPassContainedWidget() method that does what you'd expect: it returns a new ContainerWidget and gives it ownership of the contained widget. Obviously, after calling the method the original ContainerWidget becomes useless, but the method is called precisely because the original ContainerWidget is set to be destroyed, so that's not a problem. I can now use my GridWidget to display any kind of widgets, it's pretty neat! (I wrote "widget" too many times!)
I realize the "proper" way would have been to write a model, views, and delegates, but that would have required a lot more work.
EDIT: Here's my updated solution: https://gist.github.com/anonymous/a3b2d7e61c6b3e11742c