QModelIndexList的析构函数太慢了

Sla*_*kij 5 qt qabstractitemmodel qmodelindex

执行这个简单的代码片段:

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

当所选行的数量约为一百万时,需要超过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();
}
Run Code Online (Sandbox Code Playgroud)

有人有解决方案吗?有没有办法在没有创建的情况下获取所选行的索引QModelIndexList,或者我可以以某种方式加速破坏?

Rei*_*ica 5

QList会,不幸的是,在每一个模型索引进行内存分配和删除.出于某种原因,在您的平台上,重新分配非常缓慢.

作为一种变通方法,您可以在工作线程中运行释放,利用QList隐式共享类的事实.

这假设QModelIndex在非gui线程中删除a是安全的.您必须审核您的代码和相关的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.
Run Code Online (Sandbox Code Playgroud)

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.
Run Code Online (Sandbox Code Playgroud)

关于可移动类型的λ捕获技术,请参阅此问题.

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));
}
Run Code Online (Sandbox Code Playgroud)

CopyMoves类实现了其移动类data时拷贝结构件.这是使用的可怕黑客std::auto_ptr(不要使用auto_ptr!).非空CopyMoves::data成员将在工作线程中被破坏.CopyMoves保持为空的另外两个实例data将在主线程中被破坏.