I am using QSignalMapper with Qt 4.8. Now I am making network requests like below:
// start the request
QNetworkRequest request(url);
QNetworkReply* reply = networkManager->get(request);
// connect signals using QSignalMapper
QSignalMapper* signalMapper = new QSignalMapper(reply);
connect(signalMapper, SIGNAL(mapped(QObject*)),this, SLOT(onFeedRetrieved(QObject*)), Qt::UniqueConnection);
connect(reply,SIGNAL(finished()),signalMapper, SLOT(map())); // connect to the signal mapper
signalMapper->setMapping(reply, dataModel); // set the mapping (the mapping should be automatically removed when reply is destroyed)
I am doing this for each request I make, I connect the QSignalMapper with my slots each time. Is there a more elegant solution that does the same thing, perhaps using one QSignalMapper?
One simple way to do it would be to set the
dataModel
as a property on the reply.Keep the network manager and other objects by value, not by pointer - the pointer is an extra indirection and completely unnecessary in most cases.
Below is a complete C++11 example that works in both Qt 4 and 5.
You can only use the
QSignalMapper
if there's a 1:1 mapping between adataModel
instance and a reply. If one data model is used for multiple replies, it won't work.If you're really concerned about allocation count, then using the property system has a bit more overhead: setting the first property on an object performs at least two allocations - an internal class, and a data segment for
QMap
. So that's 2N allocations. In comparison, adding a mapping to aQSignalMapper
performs an amortized log(N) allocations. Otherwise,QSignalMapper
is useless.In Qt 5 using it would be outright an antipattern since you can connect to
std::bind
or a lambda. In any case, it'd be much nicer ifQSignalMapper
mapped to aQVariant
.Adding a first connection to an object also allocates a (different) internal class. To avoid this potential cost, you should avoid adding connections to objects you create often. It's preferable to connect once to the
QNetworkManager::finished(QNetworkReply*)
signal rather than connecting to everyQNetworkReply::finished()
. Alas, this saving is gone once you use queued connections: they, at the moment, cost an extra allocation for every argument passed to the slot. This is only a shortcoming of the current implementation, not an architectural limitation; it can be removed in a subsequent minor Qt release (if myself or someone else gets to it).