Почему этот локальный QMultiMap отключается при изменении?

Чтобы дать некоторую предысторию: в моем проекте я поместил точку останова отладки внутри, потому что я хотел увидеть, могу ли я обнаружить какие-либо случаи, когда неявно разделяемые QMaps отключались из-за недосмотра, например, используя find когда constFindможно было использовать. Я не ожидал, что попаду в него очень часто, потому что в основном я передаю контейнеры по константной ссылке (в качестве побочного примечания, очевидно, есть инструмент под названием "clazy" для поиска таких вещей).

Затем я смотрел на некоторый внутренний код Qt v5.9.3, который вызвал отсоединение. Трассировка стека показывает, что мы отключаемся от первой строки insertMulti функция, которая вызывается здесь:

      // return true if accepted (consumed)
bool QGestureManager::filterEvent(QWidget *receiver, QEvent *event)
{
    QMap<Qt::GestureType, int> types;
    QMultiMap<QObject *, Qt::GestureType> contexts;
    QWidget *w = receiver;
    typedef QMap<Qt::GestureType, Qt::GestureFlags>::const_iterator ContextIterator;
    if (!w->d_func()->gestureContext.isEmpty()) {
        for(ContextIterator it = w->d_func()->gestureContext.constBegin(),
            e = w->d_func()->gestureContext.constEnd(); it != e; ++it) {
            types.insert(it.key(), 0);
            contexts.insertMulti(w, it.key());
        }
    }
    // find all gesture contexts for the widget tree
    w = w->isWindow() ? 0 : w->parentWidget();
    while (w)
    {
        for (ContextIterator it = w->d_func()->gestureContext.constBegin(),
             e = w->d_func()->gestureContext.constEnd(); it != e; ++it) {
            if (!(it.value() & Qt::DontStartGestureOnChildren)) {
                if (!types.contains(it.key())) {
                    types.insert(it.key(), 0);
                    contexts.insertMulti(w, it.key()); // Why does this trigger a detach?
                }
            }
        }
        if (w->isWindow())
            break;
        w = w->parentWidget();
    }
    return contexts.isEmpty() ? false : filterEventThroughContexts(contexts, event);
}

Почему локальный QMultiMap, который никогда не копировался, стал неявно совместно используемым и его нужно было отсоединить?


Моя теория

Это может быть не актуально, но размер contexts был нулевым на этой линии.

Я предполагаю, что отсоединение было вызвано какой-то оптимизацией, связанной с пустыми картами, но я не уверен. Я заметил, что получаю гораздо меньше попаданий, помещая точку останова отладки внутри части QMap::detach_helper который выполняется только для непустых карт (то есть внутри условных if (d->header.left))

1 ответ

Q(Multi)Map отключается не на каждой вставке, а только на первой, когда карта еще не инициализирована:

      QMultiMap<int, int> mm;
mm.insert(42, 43);  // detach_helper is called because the container needs to be initialized
mm.insert(43, 44);  // detach_helper is not called
Другие вопросы по тегам