10

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?

demonplus
  • 5,036
  • 11
  • 41
  • 56
bdesham
  • 13,980
  • 10
  • 70
  • 116

2 Answers2

4

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 :)

hank
  • 8,315
  • 2
  • 29
  • 47
  • That is interesting, I did not know you could do that. However, I don't think it improves the original. Its much tidier to use QMetaData / qRegisterMetaType since that is exactly the reason of the mechanism : ), plus you keep your auto complete as well :)) – code_fodder Feb 11 '15 at 09:03
  • I suppose the OP asked not about how to send `QSharedPointer` objects via signal-slot mechanism (in this case `qRegisterMetaType` really should be used) but how to pass a `QSharedPointer` object to the `connect` function. – hank Feb 11 '15 at 09:07
  • But "How to send QSharedPointer via signal-slot" and "how to pass a QSharedPointer object to the connect function".... are basically the same thing since connect is part of the signal-slot mechanism. But anyway, I quite like like what you have done, its outside the box, but I was just pointing out that its not the best way (perhaps just in my opinion). – code_fodder Feb 11 '15 at 09:31
2

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);
}
bdesham
  • 13,980
  • 10
  • 70
  • 116