Is it possible, and if so, how can I create a signal/slot in Qt that is a const reference to a shared_ptr? I want a signal that looks like this:
void signal( shared_ptr<SomeClass> const & )
I know how to do this without a constant reference, that is simply the type shared_ptr<SomeClass>
but for efficiency* reasons I'd like to avoid the copying. The same syntax for reference type isn't working:
Q_DECLARE_METATYPE(shared_ptr<SomeClass> const &)
qRegisterMetaType<shared_ptr<SomeClass> const&>();
Many of the standard APIs have QString const &
so I assume it is fundamentally possible and I just can't figure out the syntax.
**The biggest problem for performance is not the copying time, but the amount of mutex locking/unlocking as the object is copied to every receiver -- there are lots of them. As multiple threads use the object this introduces a noticeable slow-down/bottleneck. If the shared_ptr does in fact just use an atomic op this cost is also trivial, the general question about const reference in signals remains however.*
shared_ptr is now part of the C++11 Standard, as std::shared_ptr . Starting with Boost release 1.53, shared_ptr can be used to hold a pointer to a dynamically allocated array. This is accomplished by using an array type ( T[] or T[N] ) as the template parameter.
This ensures that truly independent components can be created with Qt. You can connect as many signals as you want to a single slot, and a signal can be connected to as many slots as you need. It is even possible to connect a signal directly to another signal.
In Qt, we have an alternative to the callback technique: We use signals and slots. A signal is emitted when a particular event occurs. Qt's widgets have many predefined signals, but we can always subclass widgets to add our own signals to them. A slot is a function that is called in response to a particular signal.
Defined in header <memory> template< class T > class shared_ptr; (since C++11) std::shared_ptr is a smart pointer that retains shared ownership of an object through a pointer. Several shared_ptr objects may own the same object.
So far I have found that I can simply do this:
Q_DECLARE_METATYPE(shared_ptr<SomeClass>)
qRegisterMetaType<shared_ptr<SomeClass> >();
qRegisterMetaType<shared_ptr<SomeClass> >("std::shared_ptr<SomeClass>const&");
I'm trying to verify now whether this truly works correctly. The documentation here isn't clear on what actually happens. It appears that the const reference type in a signal/slot will just be marshalled as a normal shared_ptr<SomeClass>
, which is totally okay here. Having some sort of guarantee that this is supposed to work as such would be nice however.
I have the feeling that the simple shared_ptr<SomeClass>
version is all that is needed and it is the boost
namespace that is interfering with the signals. The second version appears just to register the signal in the global namespace for easier use.
I can confirm, from testing, that the const &
part is, as alluded to, completely ignored in queued connections. Each connected slot gets a new copy of the object. This is very unfortunate. :(
Further tests show that the &
is used for the slot, but in an unusual fashion. The copy of the object is still created for the queued connection, but if you don't use a reference another copy will be created for the call.
Thus there although every connect
will end up copying the data for a queued connection, the references still help a bit. And also if you do have a few signals sent locally (same thread) you may avoid even more copying.
According to one of the answer in this question Argument type for Qt signal and slot, does const reference qualifiers matters? , for a queued connection, the object is copied regardless of how you connect the signal and slot.
Since you are using multiple threads, the connection is queued. If you fear the mutex cost, try using SomeClass * directly.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With