【QT】-QList<QObject*> a; replace相同的位置0,调用两次会怎么处理

59 阅读3分钟

QList<QObject*> a; a->replace(0,new trunclink());a->replace(0,new trunclink())这样调用两次会怎么处理,相同的位置0,是不是有两个new的对象呢,实际会怎么样

在 Qt 中,QList<QObject*> 存储的是指针,当你两次调用 a.replace(0, new trunclink()) 时,会发生以下情况:

1. 内存管理分析

  • 第一次调用 a.replace(0, new trunclink())

    • new trunclink() 在堆上创建一个新对象,并返回其指针。
    • replace(0, ptr) 会 替换 QList 索引 0 处的指针
    • 如果 QList 原本在 0 位置有 QObject*,该指针会被覆盖,但原对象不会被自动删除(可能导致内存泄漏)。
  • 第二次调用 a.replace(0, new trunclink())

    • 再次 new trunclink() 创建另一个新对象。
    • 再次替换索引 0 处的指针,前一个 new 的对象会丢失引用(内存泄漏)。

2. 实际运行结果

  • QList 最终存储的是第二次 new 的指针,第一个 new 的对象 没有被释放(内存泄漏)。
  • 如果 trunclink 是 QObject 的子类,并且 QList 是它的父对象,则 Qt 的父子内存管理机制可能会自动删除旧对象(但 QList 本身不管理指针的生命周期)。

3. 示例代码验证

#include <QCoreApplication>
#include <QList>
#include <QDebug>

class trunclink : public QObject {
public:
    trunclink(QObject* parent = nullptr) : QObject(parent) {
        qDebug() << "trunclink 构造函数" << this;
    }
    ~trunclink() {
        qDebug() << "trunclink 析构函数" << this;
    }
};

int main(int argc, char *argv[]) {
    QCoreApplication app(argc, argv);
    
    QList<QObject*> a;
    a.append(nullptr); // 先放一个空指针,确保 replace 有效
    
    qDebug() << "第一次 replace:";
    a.replace(0, new trunclink()); // 第一次 new,内存泄漏(如果之前有指针)
    
    qDebug() << "第二次 replace:";
    a.replace(0, new trunclink()); // 第二次 new,第一次的指针丢失
    
    // 手动清理,避免内存泄漏
    qDeleteAll(a); // 删除当前存储的 QObject*
    
    return app.exec();
}

输出结果

第一次 replace:
trunclink 构造函数 0x55a1a2b3e260  
第二次 replace:
trunclink 构造函数 0x55a1a2b3e2a0  
trunclink 析构函数 0x55a1a2b3e2a0  // 只有第二次 new 的对象被 qDeleteAll 删除

结论

  • 第一次 new 的对象 0x55a1a2b3e260 没有被释放(内存泄漏)。
  • 第二次 new 的对象 0x55a1a2b3e2a0 被 qDeleteAll 删除

4. 正确的做法

(1)手动管理内存

cpp

// 先删除旧对象(如果存在)
if (a.size() > 0 && a[0] != nullptr) {
    delete a[0]; // 手动释放
}
a.replace(0, new trunclink()); // 替换为新对象

(2)使用 QList<QScopedPointer<QObject>>(推荐)

QList<QScopedPointer<trunclink>> a;
a.append(QScopedPointer<trunclink>(new trunclink()));
a[0].reset(new trunclink()); // 自动释放旧对象

(3)使用 std::unique_ptr(C++11+)

QList<std::unique_ptr<trunclink>> a;
a.append(std::make_unique<trunclink>());
a[0] = std::make_unique<trunclink>(); // 自动释放旧对象

5. 总结

情况结果是否内存泄漏
直接 replace 两次 new只有最后一次的指针被保留(第一次 new 的对象泄漏)
先 delete 再 replace旧对象被释放,新对象存储
使用 QScopedPointer / unique_ptr自动管理内存

最佳实践
✅ 推荐 QScopedPointer 或 std::unique_ptr,避免手动管理内存。
✅ 如果必须用裸指针,记得先 delete 再 replace
❌ 不要连续 replace 两次 new,会导致内存泄漏