为什么这个本地 QMultiMap 在修改时分离?
Why is this local QMultiMap detaching when modified?
提供一些背景信息:在我的项目中,我在 QMap::detach_helper
中放置了一个调试断点,因为我想看看是否可以发现隐式共享 QMaps 由于疏忽而分离时的任何事件,例如在可以使用 constFind
时使用 find
。我没想到会经常遇到它,因为大多数情况下我都是通过 const 引用传递容器(作为旁注,显然有一个名为“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
提供一些背景信息:在我的项目中,我在 QMap::detach_helper
中放置了一个调试断点,因为我想看看是否可以发现隐式共享 QMaps 由于疏忽而分离时的任何事件,例如在可以使用 constFind
时使用 find
。我没想到会经常遇到它,因为大多数情况下我都是通过 const 引用传递容器(作为旁注,显然有一个名为“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