Qt QList - removeAll 释放内存
Qt QList - removeAll deallocating memory
我有一个 QList
的 MyClass
个这样的指针:
QList<MyClass*> myList;
当我调用 myList.removeAll(someObjPtr);
时,它不只是从 QList
中删除指针,它在内部对它们调用 delete。有没有办法解决这个问题,或者是否有替代的 QList
方法可以只删除元素而不释放它们?
编辑:removeAll 的内部结构:
template <typename T>
Q_OUTOFLINE_TEMPLATE int QList<T>::removeAll(const T &_t)
{
int index = indexOf(_t);
if (index == -1)
return 0;
const T t = _t;
detach();
Node *i = reinterpret_cast<Node *>(p.at(index));
Node *e = reinterpret_cast<Node *>(p.end());
Node *n = i;
node_destruct(i);
while (++i != e) {
if (i->t() == t)
node_destruct(i);
else
*n++ = *i;
}
int removedCount = e - n;
d->end -= removedCount;
return removedCount;
}
如您所见,它会调用 node_destruct,它会执行以下操作:
template <typename T>
Q_INLINE_TEMPLATE void QList<T>::node_destruct(Node *n)
{
if (QTypeInfo<T>::isLarge || QTypeInfo<T>::isStatic) delete reinterpret_cast<T*>(n->v);
else if (QTypeInfo<T>::isComplex) reinterpret_cast<T*>(n)->~T();
}
如您所见,正在调用删除。
QList
与 Qt 3 的 QPtrList
.
无关
QList
方法中的 None 以特殊方式解释存储的指针。你一定是测试错了。例如,下面的代码愉快地泄漏了两个 C 实例并且从未删除它们。
也许您从 QtAlgorithms
想到了 qDeleteAll
?这个 将 删除实例。
请注意,QList
的实现可能会分配每个项目的内存来存储您的实例,并会在适当的时候释放该内存。在任何情况下 QList
实现都不会删除您存储在列表中的指针:QList
解释存储数据的唯一方法是通过它的类型,然后它只是决定项目是否是内存可移动的, 以及它们是否适合 void*
还是需要单独分配。事实上,所有指针类型都存储在QList
中,就好像它是一个QVector
一样,在开头和结尾添加了一点空间,使push_front
和 push_back
已摊销 O(1) 成本。
#include <QtCore>
struct C {
static int ctr;
C() { ctr ++; }
~C() { ctr --; qDebug() << (void*)this << "C instance destructed"; }
};
int C::ctr;
int main() {
auto c1 = new C, c2 = new C;
auto list1 = QList<C*>() << c1 << c2;
list1.removeAll(c1); // doesn't delete the pointed-to objects
list1.removeAll(c2);
Q_ASSERT(list1.isEmpty());
Q_ASSERT(C::ctr == 2);
// we'll happily leak both instances above
auto list2 = QList<C*>() << new C << new C << new C;
qDeleteAll(list2); // invokes delete on all objects
Q_ASSERT(C::ctr == 2);
}
node_destruct
不会删除指针QLists指向的对象。如果仔细观察,它只会删除大型和静态类型的 n->v
。 QList 内部在堆上分配大型和静态类型,因此删除是必要的。
对于指针类型,QTypeInfo<T>
特化是:
template <typename T>
class QTypeInfo<T*>
{
public:
enum {
isPointer = true,
isComplex = false,
isStatic = false,
isLarge = false,
isDummy = false
};
};
如您所见,指针既不是大指针也不是静态指针,因此不会被删除
我有一个 QList
的 MyClass
个这样的指针:
QList<MyClass*> myList;
当我调用 myList.removeAll(someObjPtr);
时,它不只是从 QList
中删除指针,它在内部对它们调用 delete。有没有办法解决这个问题,或者是否有替代的 QList
方法可以只删除元素而不释放它们?
编辑:removeAll 的内部结构:
template <typename T>
Q_OUTOFLINE_TEMPLATE int QList<T>::removeAll(const T &_t)
{
int index = indexOf(_t);
if (index == -1)
return 0;
const T t = _t;
detach();
Node *i = reinterpret_cast<Node *>(p.at(index));
Node *e = reinterpret_cast<Node *>(p.end());
Node *n = i;
node_destruct(i);
while (++i != e) {
if (i->t() == t)
node_destruct(i);
else
*n++ = *i;
}
int removedCount = e - n;
d->end -= removedCount;
return removedCount;
}
如您所见,它会调用 node_destruct,它会执行以下操作:
template <typename T>
Q_INLINE_TEMPLATE void QList<T>::node_destruct(Node *n)
{
if (QTypeInfo<T>::isLarge || QTypeInfo<T>::isStatic) delete reinterpret_cast<T*>(n->v);
else if (QTypeInfo<T>::isComplex) reinterpret_cast<T*>(n)->~T();
}
如您所见,正在调用删除。
QList
与 Qt 3 的 QPtrList
.
QList
方法中的 None 以特殊方式解释存储的指针。你一定是测试错了。例如,下面的代码愉快地泄漏了两个 C 实例并且从未删除它们。
也许您从 QtAlgorithms
想到了 qDeleteAll
?这个 将 删除实例。
请注意,QList
的实现可能会分配每个项目的内存来存储您的实例,并会在适当的时候释放该内存。在任何情况下 QList
实现都不会删除您存储在列表中的指针:QList
解释存储数据的唯一方法是通过它的类型,然后它只是决定项目是否是内存可移动的, 以及它们是否适合 void*
还是需要单独分配。事实上,所有指针类型都存储在QList
中,就好像它是一个QVector
一样,在开头和结尾添加了一点空间,使push_front
和 push_back
已摊销 O(1) 成本。
#include <QtCore>
struct C {
static int ctr;
C() { ctr ++; }
~C() { ctr --; qDebug() << (void*)this << "C instance destructed"; }
};
int C::ctr;
int main() {
auto c1 = new C, c2 = new C;
auto list1 = QList<C*>() << c1 << c2;
list1.removeAll(c1); // doesn't delete the pointed-to objects
list1.removeAll(c2);
Q_ASSERT(list1.isEmpty());
Q_ASSERT(C::ctr == 2);
// we'll happily leak both instances above
auto list2 = QList<C*>() << new C << new C << new C;
qDeleteAll(list2); // invokes delete on all objects
Q_ASSERT(C::ctr == 2);
}
node_destruct
不会删除指针QLists指向的对象。如果仔细观察,它只会删除大型和静态类型的 n->v
。 QList 内部在堆上分配大型和静态类型,因此删除是必要的。
对于指针类型,QTypeInfo<T>
特化是:
template <typename T>
class QTypeInfo<T*>
{
public:
enum {
isPointer = true,
isComplex = false,
isStatic = false,
isLarge = false,
isDummy = false
};
};
如您所见,指针既不是大指针也不是静态指针,因此不会被删除