QModelIndexList 的析构函数太慢

Destructor of QModelIndexList is too slow

这个简单片段的执行:

{
  QModelIndexList sel = ui->tableView->selectionModel()->selectedRows(0);
  sel.at(0).isValid(); // To prevent removing the previous line by optimization
}

选中行数在一百万左右时,需要30秒以上。 QModelIndex 列表的构造几乎是立即的,但销毁需要永远。 花在这个函数上的时间:

template <typename T>
Q_INLINE_TEMPLATE void QList<T>::node_destruct(Node *from, Node *to)
{
    if (QTypeInfo<T>::isLarge || QTypeInfo<T>::isStatic)
        while(from != to) --to, delete reinterpret_cast<T*>(to->v);
    else if (QTypeInfo<T>::isComplex)
        while (from != to) --to, reinterpret_cast<T*>(to)->~T();
}

有人有解决办法吗?有什么方法可以在不创建 QModelIndexList 的情况下获取选定行的索引,或者我可以以某种方式加速销毁吗?

不幸的是,

A QList 将对每个模型索引执行内存分配和删除。由于某种原因,在您的平台上,重新分配非常慢。

作为一种变通方法,您可以 运行 在工作线程中重新分配,利用 QList 是隐式共享的 class.

这一事实

这假定在非 gui 线程中删除 QModelIndex 是安全的。您必须审核您的代码和相关的 Qt 代码以确定这一点。

C++11

auto sel{ui->tableView->selectionModel()->selectedRows(0)};
// Use sel.
sel.at(0).isValid();
// Deallocate in a separate thread.
QtConcurrent::run(std::bind([] (QModelIndexList& p) {}, std::move(sel)));
// At this point, sel has been moved from and its destruction is trivial.

C++14

auto sel{ui->tableView->selectionModel()->selectedRows(0)};
// Use sel.
sel.at(0).isValid();
// Deallocate in a separate thread.
QtConcurrent::run([sel{std::move(sel)}] {});
// At this point, sel has been moved from and its destruction is trivial.

有关可移动类型的 lambda 捕获技术,请参阅 this question

C++98

template <typename T> class CopyMoves {
   mutable T data;
public:
   CopyMoves(T & old) { std::swap(data, old); }
   CopyMoves(const CopyMoves & old) { std::swap(data, old.data); }
   void operator()() {}
};

int main() {
   QModelIndexList sel;
   QtConcurrent::run(CopyMoves<QModelIndexList>(sel));
}

CopyMoves class 实现了一个 class,它在复制构造时移动其 data 成员。这是 std::auto_ptr 使用的可怕 hack(不要使用 auto_ptr!)。非空 CopyMoves::data 成员将在工作线程中销毁。 CopyMoves 的另外两个实例,持有空 data,将在主线程中销毁。