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
,将在主线程中销毁。
这个简单片段的执行:
{
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
,将在主线程中销毁。