My application contained several functions like this:
void SomeClass::set_data_provider(DataProvider *data_provider)
{
connect(data_provider, SIGNAL(data_available(int)),
this, SLOT(data_available(int)));
}
To avoid passing raw pointers around I have changed all occurrences of DataProvider *
to QSharedPointer<DataProvider>
. The latter is almost a drop-in replacement for the former, except that you can’t pass a QSharedPointer to QObject::connect
. I worked around this by extracting a raw pointer from the QSharedPointer:
void SomeClass::set_data_provider(QSharedPointer<DataProvider> data_provider)
{
connect(data_provider.data(), SIGNAL(data_available(int)),
this, SLOT(data_available(int)));
}
This seems to work fine but it looks inelegant and I’m wary of accessing the raw pointer like this. Is there a better way to connect to an object that’s being passed around in a QSharedPointer?
You can create a custom connect function:
template<class T> bool
my_connect(const QSharedPointer<T> &sender,
const char *signal,
const QObject *receiver,
const char *method,
Qt::ConnectionType type = Qt::AutoConnection)
{
return QObject::connect(sender.data(), signal, receiver, method, type);
}
And use it like this:
QSharedPointer<MyObject> shared(new MyObject);
my_connect(shared, SIGNAL(my_signal()), this, SLOT(my_slot()));
The only problem is that in both yours and mine solutions you will lose Qt Creator autocomplete for the native connect function.
P.S. As for me, I wouldn't change your code. I think it's fine :)
For completeness, here is an extension of @hank’s answer. I provide six connect
-like functions:
connect_from_pointer
takes a QSharedPointer as its first argument and the usual QObject *
as its third argument.
connect_to_pointer
takes the usual QObject *
as its first argument and a QSharedPointer as its third argument.
connect_pointers
takes QSharedPointers for both parameters.
There are two versions of each of these: one that accepts the SIGNAL()
/SLOT()
syntax and one that accepts the (recommended) function pointers.
These are syntactically atrocious, but that’s templates for you.
template<class T>
QMetaObject::Connection connect_from_pointer(
const QSharedPointer<T>& sender,
const char *signal,
const QObject *receiver,
const char *method,
Qt::ConnectionType type = Qt::AutoConnection)
{
return QObject::connect(sender.data(), signal, receiver, method, type);
}
template <typename Func1, typename Func2>
QMetaObject::Connection connect_from_pointer(
const QSharedPointer<typename QtPrivate::FunctionPointer<Func1>::Object>& sender,
Func1 signal,
const typename QtPrivate::FunctionPointer<Func2>::Object *receiver,
Func2 slot,
Qt::ConnectionType type = Qt::AutoConnection)
{
return QObject::connect(sender.data(), signal, receiver, slot, type);
}
template<class T>
QMetaObject::Connection connect_to_pointer(
const QObject *sender,
const char *signal,
const QSharedPointer<T>& receiver,
const char *method,
Qt::ConnectionType type = Qt::AutoConnection)
{
return QObject::connect(sender, signal, receiver.data(), method, type);
}
template <typename Func1, typename Func2>
QMetaObject::Connection connect_to_pointer(
const typename QtPrivate::FunctionPointer<Func1>::Object *sender,
Func1 signal,
const QSharedPointer<typename QtPrivate::FunctionPointer<Func2>::Object>& receiver,
Func2 slot,
Qt::ConnectionType type = Qt::AutoConnection)
{
return QObject::connect(sender, signal, receiver.data(), slot, type);
}
template<class T, class U>
QMetaObject::Connection connect_pointers(
const QSharedPointer<T>& sender,
const char *signal,
const QSharedPointer<U>& receiver,
const char *method,
Qt::ConnectionType type = Qt::AutoConnection)
{
return QObject::connect(sender.data(), signal, receiver.data(), method, type);
}
template <typename Func1, typename Func2>
QMetaObject::Connection connect_pointers(
const QSharedPointer<typename QtPrivate::FunctionPointer<Func1>::Object>& sender,
Func1 signal,
const QSharedPointer<typename QtPrivate::FunctionPointer<Func2>::Object>& receiver,
Func2 slot,
Qt::ConnectionType type = Qt::AutoConnection)
{
return QObject::connect(sender.data(), signal, receiver.data(), slot, type);
}