微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

为什么这个本地 QMultiMap 在修改时会分离?

如何解决为什么这个本地 QMultiMap 在修改时会分离?

提供一些背景知识:在我的项目中,我在 QMap::detach_helper 中放置了一个调试断点,因为我想看看当隐式共享的 QMap 由于疏忽而分离时是否可以发现任何事件,例如当可以使用 find 时使用 constFind。我没想到会经常遇到它,因为大多数情况下我是通过常量引用传递容器(作为旁注,显然有一个名为“clazy”的工具可以找到这些东西)。

然后我查看了一些触发分离的内部 Qt v5.9.3 代码。堆栈跟踪显示我们正在与 insertMulti 函数的第一行分离,该函数contexts调用

// 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——从未被复制——会隐式共享并需要分离?


我的理论

这可能不相关,但该行 contexts 的大小为零。

我的猜测是分离是由与空地图相关的某种优化引起的,但我不确定。我确实注意到,通过将调试断点放在 QMap::detach_helper 的部分内,我得到的点击次数要少得多,该部分只对非空映射执行(即,在条件 if (d->header.left) 内)

解决方法

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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。