connect изнутри

Можно ли передавать параметры в сигнале (или слоте) по указателю - ответ можно, можно ли по ссылке - ответ можно.

Вот реализация функции connect в Qt 4.8.1:

bool QObject::connect(const QObject *sender, const char *signal,
                      const QObject *receiver, const char *method,
                      Qt::ConnectionType type)
{
    {
        const void *cbdata[] = { sender, signal, receiver, method, &type };
        if (QInternal::activateCallbacks(QInternal::ConnectCallback, (void **) cbdata))
            return true;
    }

#ifndef QT_NO_DEBUG
    bool warnCompat = true;
#endif
    if (type == Qt::AutoCompatConnection) {
        type = Qt::AutoConnection;
#ifndef QT_NO_DEBUG
        warnCompat = false;
#endif
    }

    if (sender == 0 || receiver == 0 || signal == 0 || method == 0) {
        qWarning("QObject::connect: Cannot connect %s::%s to %s::%s",
                 sender ? sender->metaObject()->className() : "(null)",
                 (signal && *signal) ? signal 1 : "(null)",
                 receiver ? receiver->metaObject()->className() : "(null)",
                 (method && *method) ? method 1 : "(null)");
        return false;
    }
    QByteArray tmp_signal_name;

    if (!check_signal_macro(sender, signal, "connect", "bind"))
        return false;
    const QMetaObject *smeta = sender->metaObject();
    const char *signal_arg = signal;
      signal; //skip code
    int signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signal, false);
    if (signal_index < 0) {
        // check for normalized signatures
        tmp_signal_name = QMetaObject::normalizedSignature(signal - 1);
        signal = tmp_signal_name.constData()   1;

        smeta = sender->metaObject();
        signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signal, false);
    }
    if (signal_index < 0) {
        // re-use tmp_signal_name and signal from above

        smeta = sender->metaObject();
        signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signal, true);
    }
    if (signal_index < 0) {
        err_method_notfound(sender, signal_arg, "connect");
        err_info_about_objects("connect", sender, receiver);
        return false;
    }
    signal_index = QMetaObjectPrivate::originalClone(smeta, signal_index);
    int signalOffset, methodOffset;
    computeOffsets(smeta, &signalOffset, &methodOffset);
    int signal_absolute_index = signal_index   methodOffset;
    signal_index  = signalOffset;

    QByteArray tmp_method_name;
    int membcode = extract_code(method);

    if (!check_method_code(membcode, receiver, method, "connect"))
        return false;
    const char *method_arg = method;
      method; // skip code

    const QMetaObject *rmeta = receiver->metaObject();
    int method_index_relative = -1;
    switch (membcode) {
    case QSLOT_CODE:
        method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(&rmeta, method, false);
        break;
    case QSIGNAL_CODE:
        method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(&rmeta, method, false);
        break;
    }

    if (method_index_relative < 0) {
        // check for normalized methods
        tmp_method_name = QMetaObject::normalizedSignature(method);
        method = tmp_method_name.constData();

        // rmeta may have been modified above
        rmeta = receiver->metaObject();
        switch (membcode) {
        case QSLOT_CODE:
            method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(&rmeta, method, false);
            if (method_index_relative < 0)
                method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(&rmeta, method, true);
            break;
        case QSIGNAL_CODE:
            method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(&rmeta, method, false);
            if (method_index_relative < 0)
                method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(&rmeta, method, true);
            break;
        }
    }

    if (method_index_relative < 0) {
        err_method_notfound(receiver, method_arg, "connect");
        err_info_about_objects("connect", sender, receiver);
        return false;
    }

    if (!QMetaObject::checkConnectArgs(signal, method)) {
        qWarning("QObject::connect: Incompatible sender/receiver arguments"
                 "\n        %s::%s --> %s::%s",
                 sender->metaObject()->className(), signal,
                 receiver->metaObject()->className(), method);
        return false;
    }

    int *types = 0;
    if ((type == Qt::QueuedConnection)
            && !(types = queuedConnectionTypes(smeta->method(signal_absolute_index).parameterTypes())))
        return false;

#ifndef QT_NO_DEBUG
    if (warnCompat) {
        QMetaMethod smethod = smeta->method(signal_absolute_index);
        QMetaMethod rmethod = rmeta->method(method_index_relative   rmeta->methodOffset());
        check_and_warn_compat(smeta, smethod, rmeta, rmethod);
    }
#endif

    // вот здесь мы похоже имеем уже только индексы методов (функций) вместо строк

    if (!QMetaObjectPrivate::connect(sender, signal_index, receiver, method_index_relative, rmeta ,type, types))
        return false;
    const_cast(sender)->connectNotify(signal - 1);
    return true;
}

Тут происходят подготовительные действия: такие как вычисление номеров сигналов/слотов по их текстовым представлениям. В конце вызывается  QMetaObjectPrivate::connect, которому уже передаются индексы функций сигнала и слота.

У каждого QObject есть закрытая от использования разработчиками часть: класс  QObjectPrivate.

Надо сразу рассмотреть класс QObjectPrivate
class Q_CORE_EXPORT QObjectPrivate : public QObjectData
{
    Q_DECLARE_PUBLIC(QObject)

public:
    struct ExtraData
    {
        ExtraData() {}
#ifndef QT_NO_USERDATA
        QVector<QObjectUserData *> userData;
#endif
        QList<QByteArray> propertyNames;
        QList<QVariant> propertyValues;
    };

    typedef void (*StaticMetaCallFunction)(QObject *, QMetaObject::Call, int, void **);
    struct Connection
    {
        QObject *sender;
        QObject *receiver;
        StaticMetaCallFunction callFunction;
        // The next pointer for the singly-linked ConnectionList
        Connection *nextConnectionList;
        //senders linked list
        Connection *next;
        Connection **prev;
        QBasicAtomicPointer<int> argumentTypes;
        ushort method_offset;
        ushort method_relative;
        ushort connectionType : 3; // 0 == auto, 1 == direct, 2 == queued, 4 == blocking
        ~Connection();
        int method() const { return method_offset + method_relative; }
    };
    // ConnectionList is a singly-linked list
    struct ConnectionList {
        ConnectionList() : first(0), last(0) {}
        Connection *first;
        Connection *last;
    };

    struct Sender
    {
        QObject *sender;
        int signal;
        int ref;
    };


    QObjectPrivate(int version = QObjectPrivateVersion);
    virtual ~QObjectPrivate();
    void deleteChildren();

    void setParent_helper(QObject *);
    void moveToThread_helper();
    void setThreadData_helper(QThreadData *currentData, QThreadData *targetData);
    void _q_reregisterTimers(void *pointer);

    bool isSender(const QObject *receiver, const char *signal) const;
    QObjectList receiverList(const char *signal) const;
    QObjectList senderList() const;

    void addConnection(int signal, Connection *c);
    void cleanConnectionLists();

#ifdef QT3_SUPPORT
    void sendPendingChildInsertedEvents();
#endif

    static inline Sender *setCurrentSender(QObject *receiver,
                                    Sender *sender);
    static inline void resetCurrentSender(QObject *receiver,
                                   Sender *currentSender,
                                   Sender *previousSender);
#ifdef QT_JAMBI_BUILD
    static int *setDeleteWatch(QObjectPrivate *d, int *newWatch);
    static void resetDeleteWatch(QObjectPrivate *d, int *oldWatch, int deleteWatch);
#endif
    static void clearGuards(QObject *);

    static QObjectPrivate *get(QObject *o) {
        return o->d_func();
    }

    int signalIndex(const char *signalName) const;
    inline bool isSignalConnected(uint signalIdx) const;

public:
    QString objectName;
    ExtraData *extraData;    // extra data set by the user
    QThreadData *threadData; // id of the thread that owns the object

    QObjectConnectionListVector *connectionLists;

    Connection *senders;     // linked list of connections connected to this object
    Sender *currentSender;   // object currently activating the object
    mutable quint32 connectedSignals[2];

#ifdef QT3_SUPPORT
    QVector< QWeakPointer<QObject> > pendingChildInsertedEvents;
#else
    // preserve binary compatibility with code compiled without Qt 3 support
    // keeping the binary layout stable helps the Qt Creator debugger
    void *unused;
#endif

    QList<QPointer<QObject> > eventFilters;
    union {
        QObject *currentChildBeingDeleted;
        QAbstractDeclarativeData *declarativeData; //extra data used by the declarative module
    };

    // these objects are all used to indicate that a QObject was deleted
    // plus QPointer, which keeps a separate list
    QAtomicPointer<QtSharedPointer::ExternalRefCountData> sharedRefcount;
#ifdef QT_JAMBI_BUILD
    int *deleteWatch;
#endif
};

Тут Connection *senders; - это указатель на одно-связанный список всех сигналов, подключенных к этому объекту.

QThreadData *threadData; // id of the thread that owns the object, то есть тут сразу вводится парадигма межпоточной безопасности владения объектами, унаследованными от QObject. И это есть крутейшая фича.

теперь собственно сам реальный QMetaObjectPrivate::connect
bool QMetaObjectPrivate::connect(const QObject *sender, int signal_index,
                                 const QObject *receiver, int method_index,
                                 const QMetaObject *rmeta, int type, int *types)
{
    QObject *s = const_cast<QObject *>(sender);
    QObject *r = const_cast<QObject *>(receiver);

    int method_offset = rmeta ? rmeta->methodOffset() : 0;
    QObjectPrivate::StaticMetaCallFunction callFunction =
        (rmeta && QMetaObjectPrivate::get(rmeta)->revision >= 6 && rmeta->d.extradata)
        ? reinterpret_cast<const QMetaObjectExtraData *>(rmeta->d.extradata)->static_metacall : 0;

    QOrderedMutexLocker locker(signalSlotLock(sender),
                               signalSlotLock(receiver));

    if (type & Qt::UniqueConnection) {
        QObjectConnectionListVector *connectionLists = QObjectPrivate::get(s)->connectionLists;
        if (connectionLists && connectionLists->count() > signal_index) {
            const QObjectPrivate::Connection *c2 =
                (*connectionLists)[signal_index].first;

            int method_index_absolute = method_index + method_offset;

            while (c2) {
                if (c2->receiver == receiver && c2->method() == method_index_absolute)
                    return false;
                c2 = c2->nextConnectionList;
            }
        }
        type &= Qt::UniqueConnection - 1;
    }

    QObjectPrivate::Connection *c = new QObjectPrivate::Connection;
    c->sender = s;
    c->receiver = r;
    c->method_relative = method_index;
    c->method_offset = method_offset;
    c->connectionType = type;
    c->argumentTypes = types;
    c->nextConnectionList = 0;
    c->callFunction = callFunction;

    QT_TRY {
        QObjectPrivate::get(s)->addConnection(signal_index, c);
    } QT_CATCH(...) {
        delete c;
        QT_RETHROW;
    }

    c->prev = &(QObjectPrivate::get(r)->senders);
    c->next = *c->prev;
    *c->prev = c;
    if (c->next)
        c->next->prev = &c->next;

    QObjectPrivate *const sender_d = QObjectPrivate::get(s);
    if (signal_index < 0) {
        sender_d->connectedSignals[0] = sender_d->connectedSignals[1] = ~0;
    } else if (signal_index < (int)sizeof(sender_d->connectedSignals) * 8) {
        sender_d->connectedSignals[signal_index >> 5] |= (1 << (signal_index & 0x1f));
    }

    return true;
}

Итак начинаем (пока хаотично) изучать код и наблюдаем,что connect создает объект на куче:

QObjectPrivate::Connection *c = new QObjectPrivate::Connection;
bool QMetaObjectPrivate::connect(const QObject *sender, int signal_index,
                                 const QObject *receiver, int method_index,
                                 const QMetaObject *rmeta, int type, int *types)
{
    QObject *s = const_cast<QObject *>(sender);
    QObject *r = const_cast<QObject *>(receiver);

    int method_offset = rmeta ? rmeta->methodOffset() : 0;
    QObjectPrivate::StaticMetaCallFunction callFunction =
        (rmeta && QMetaObjectPrivate::get(rmeta)->revision >= 6 && rmeta->d.extradata)
        ? reinterpret_cast<const QMetaObjectExtraData *>(rmeta->d.extradata)->static_metacall : 0;

    QOrderedMutexLocker locker(signalSlotLock(sender),
                               signalSlotLock(receiver));

    if (type & Qt::UniqueConnection) {
        QObjectConnectionListVector *connectionLists = QObjectPrivate::get(s)->connectionLists;
        if (connectionLists && connectionLists->count() > signal_index) {
            const QObjectPrivate::Connection *c2 =
                (*connectionLists)[signal_index].first;

            int method_index_absolute = method_index + method_offset;

            while (c2) {
                if (c2->receiver == receiver && c2->method() == method_index_absolute)
                    return false;
                c2 = c2->nextConnectionList;
            }
        }
        type &= Qt::UniqueConnection - 1;
    }

    QObjectPrivate::Connection *c = new QObjectPrivate::Connection;
    c->sender = s;
    c->receiver = r;
    c->method_relative = method_index;
    c->method_offset = method_offset;
    c->connectionType = type;
    c->argumentTypes = types;
    c->nextConnectionList = 0;
    c->callFunction = callFunction;

    QT_TRY {
        QObjectPrivate::get(s)->addConnection(signal_index, c);
    } QT_CATCH(...) {
        delete c;
        QT_RETHROW;
    }

    c->prev = &(QObjectPrivate::get(r)->senders);
    c->next = *c->prev;
    *c->prev = c;
    if (c->next)
        c->next->prev = &c->next;

    QObjectPrivate *const sender_d = QObjectPrivate::get(s);
    if (signal_index < 0) {
        sender_d->connectedSignals[0] = sender_d->connectedSignals[1] = ~0;
    } else if (signal_index < (int)sizeof(sender_d->connectedSignals) * 8) {
        sender_d->connectedSignals[signal_index >> 5] |= (1 << (signal_index & 0x1f));
    }

    return true;
}

Объект Connection по-видимому является одним из элементов списка (цепочки) из таких же объектов Connection. То есть это по-видимому двух-связанный список. Смысл очевиден (по коду): строится цепочка из объектов Connection в памяти куча (не на стеке). 

Примечание: по коду connectNotify(signal - 1);  ничего пока не делает, но это виртуальный вызов, который вы в своем наследнике QObject можете переопределить и он будет делать что-то только вам нужное.

Обращаем внимание, что prev используется как двойной указатель:
Connection *next;
Connection **prev;

С ходу разобраться во всех тонкостях сложновато. Поэтому дебажим, смотрим как меняются показания свойств. Выясняем точно, что:

method_index - это номер слота по порядку следования в h файле (см. раздел slots:), то есть как в объявлении класса, унаследованном от QObject.

signal_index - это точно как method_index только для сигналов.

void QObjectPrivate::addConnection(int signal, Connection *c)
void QObjectPrivate::addConnection(int signal, Connection *c)
{
    if (!connectionLists)
        connectionLists = new QObjectConnectionListVector();
    if (signal >= connectionLists->count())
        connectionLists->resize(signal + 1);

    ConnectionList &connectionList = (*connectionLists)[signal];
    if (connectionList.last) {
        connectionList.last->nextConnectionList = c;
    } else {
        connectionList.first = c;
    }
    connectionList.last = c;

    cleanConnectionLists();
}

connectionLists = new QObjectConnectionListVector();
connectionLists тоже создается в куче.

Примечание: кстати у QObject есть полезный вызов: dumpObjectInfo, который в режиме дебага выведет текущие слоты/сигналы объекта.

Вот этот участок кода нам показывает как вставляется (или добавляется) новый объект Connection в цепочку (он самый трудный для понимания):

// похоже, что prev это будет как-бы текущий (последний созданный), а next это указатель на предыдущий

c->prev = &(QObjectPrivate::get(r)->senders); // здесь мы сохраняем указатель на последний Connection 
// в поле prev для вновь созданного 
// изначально senders = 0

c->next = *c->prev; 

*c->prev = c; // здесь мы заменяем в QObjectPrivate указатель на Connection (т.е. senders)
// теперь он указывает на последний созданный Connection (new)

if (c->next)
	c->next->prev = &c->next;

Изначально senders равен 0. То есть еще нет ни одного созданного объекта Connection.

Когда мы создадим первый объект Connection1 его поле next будет равно нулю. Это означает, что он в цепочке один.

Когда мы создадим второй объект Connection2, то его поле next будет указывать на первый созданный Connection1. Что по терминологии немного вроде не логичнo (скорее всего это prev). Но не суть важно.

Теперь senders будет указывать на второй Connection2. 

В Connection1 поле prev будет указывать на второй Connection2.
В Connection1 поле next будет = 0 .

В Connection2 поле next будет указывать на первый Connection1.
В Connection2 поле prev будет ??? .

Таким образом у нас получается дву связанный список (по-видимому), то есть все элементы знают свой предыдущий и последующий элементы. Если соседа нет то его значение равно 0 (prev или next).

Теперь перейдем к вопросу как вызывается emit далее.