目的
一般用QMap时,直接clear就可以了。
但自己分配内存那种是不能这样操作的,自己分配的内存,还得自己释放,这一个不能忘记,堆内存是需要自己管理的。
堆内存和栈内存的区别:
栈内存(Stack Memory):用于存储局部变量和函数调用的上下文信息。它的特点是访问速度快,但容量有限,通常用于存储函数内部的临时变量和返回值。当函数调用结束时,栈内存会自动释放。
堆内存(Heap Memory):用于存储动态分配的对象和大型数据结构。它的容量较大,但访问速度较慢,需要程序员手动管理其生命周期,包括分配和释放内存。堆内存适合存储生命周期较长的对象或大量数据。
在C++中,QMap等容器通常使用堆内存来存储数据。这是因为堆内存允许程序在运行时动态地分配和释放内存,而栈内存则由于是自动管理的,不适合存储大量或动态变化的数据。QMap等容器需要存储大量的键值对,并且这些数据的大小和数量在运行时是未知的,因此使用堆内存是更合适的选择。
下面就举例说明,怎么删除比较合适
情况分析
手动申请内存
面临的情况:
#pragma execution_character_set("utf-8")
#include <iostream>
#include <QtCore/QCoreApplication>
#include <QString>
#include <QMap>
#include <QDebug>
using namespace std;
class Student
{
public:
Student(int id, const char name[100], float score)
{
qDebug("Student");
this->m_id = id;
strcpy(this->m_name, name);
this->m_score = score;
}
~Student()
{
qDebug("~Student");
}
QString getName()
{
return QString(this->m_name);
}
private:
int m_id;
char m_name[100];
float m_score;
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QMap<int, Student*> stuMaps;
Student* stu1 = new Student(1, "小明", 70);
Student* stu2 = new Student(2, "小李", 80);
Student* stu3 = new Student(3, "小刚", 90);
stuMaps.insert(1, stu1);
stuMaps.insert(2, stu2);
stuMaps.insert(3, stu3);
QMap<int, Student*>::iterator iter;
for (iter = stuMaps.begin(); iter != stuMaps.end(); iter++)
{
qDebug() << "key=" <<iter.key() << ", value=" << iter.value()->getName();
}
return a.exec();
}
代码运行情况:
手动释放内存
如何删除stuMaps呢?直接clear()的话,肯定不行,那样会导致内存泄露,QMap只负责键和值,之外的东西,它就不管了。
一种思路是先删除内存,再清理,这样分两步走,处理的比较好,如下所示:
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QMap<int, Student*> stuMaps;
Student* stu1 = new Student(1, "小明", 70);
Student* stu2 = new Student(2, "小李", 80);
Student* stu3 = new Student(3, "小刚", 90);
stuMaps.insert(1, stu1);
stuMaps.insert(2, stu2);
stuMaps.insert(3, stu3);
QMap<int, Student*>::iterator iter;
for (iter = stuMaps.begin(); iter != stuMaps.end(); iter++)
{
qDebug() << "key=" <<iter.key() << ", value=" << iter.value()->getName();
}
for (auto it = stuMaps.begin(); it != stuMaps.end(); ++it)
{
delete it.value();
it.value() = nullptr;
}
for (iter = stuMaps.begin(); iter != stuMaps.end(); iter++)
{
qDebug() << "key=" << iter.key() << ", value=" << iter.value();
}
stuMaps.clear();
for (iter = stuMaps.begin(); iter != stuMaps.end(); iter++)
{
qDebug() << "key=" << iter.key() << ", value=" << iter.value()->getName();
}
return a.exec();
}
运行情况如下:
从运行情况可知,在执行delete 时申请的student对象得到了释放,达到了目的。
推荐智能指针分配与释放内存
代码更改如下:
#pragma execution_character_set("utf-8")
#include <iostream>
#include <QtCore/QCoreApplication>
#include <QString>
#include <QMap>
#include <QDebug>
#include <Memory>
using namespace std;
class Student
{
public:
Student(int id, const char name[100], float score)
{
qDebug("Student");
this->m_id = id;
strcpy(this->m_name, name);
this->m_score = score;
}
~Student()
{
qDebug("~Student");
}
QString getName()
{
return QString(this->m_name);
}
private:
int m_id;
char m_name[100];
float m_score;
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
//QMap<int, Student*> stuMaps;
{
QMap<int, shared_ptr<Student>> stuMaps;
//Student* stu1 = new Student(1, "小明", 70);
shared_ptr<Student> stu1 = make_shared<Student>(1, "小明", 70);
//Student* stu2 = new Student(2, "小李", 80);
shared_ptr<Student> stu2 = make_shared<Student>(2, "小李", 80);
//Student* stu3 = new Student(3, "小刚", 90);
shared_ptr<Student> stu3 = make_shared<Student>(3, "小刚", 90);
stuMaps.insert(1, stu1);
stuMaps.insert(2, stu2);
stuMaps.insert(3, stu3);
QMap<int, shared_ptr<Student>>::iterator iter;
for (iter = stuMaps.begin(); iter != stuMaps.end(); iter++)
{
qDebug() << "key=" << iter.key() << ", value=" << iter.value()->getName();
}
stuMaps.clear();
for (iter = stuMaps.begin(); iter != stuMaps.end(); iter++)
{
qDebug() << "key=" << iter.key() << ", value=" << iter.value()->getName();
}
}
return a.exec();
}
运行情况如下:
从运行情况可以看到,在clear()时并未释放内存,但在退出{}时,智能指针就开始释放了这些申请对象,因为退出{}时,智能指针的生命周期结束了,这就是智能指针的作用,利用生命周期进行管理指针。
C++智能指针的主要好处包括以下几个方面:
1、防止内存泄漏:智能指针在其析构函数中自动释放所管理的内存。这意味着,一旦智能指针对象超出了作用域或被删除,它所指向的内存就会自动被释放,从而避免了内存泄漏
2、防止野指针:智能指针能够防止野指针的产生。当一个智能指针被赋予一个新的值或销毁时,它所管理的原始指针会自动变为空指针(在大多数情况下),这减少了由于悬垂指针引起的未定义行为
3、提升异常安全性:在异常处理过程中,如果函数提前返回或抛出异常,可能导致分配的内存未能被释放。智能指针能够确保即使在异常发生时,其所管理的内存也能被正确释放,提高了代码的异常安全性
4、简化资源管理:智能指针通过封装原生指针,并利用RAII(资源获取即初始化)技术,确保内存的自动释放,从而避免了手动管理动态分配内存时的复杂性和出错率
5、多线程安全:在多线程环境下,智能指针可以减少因多线程操作共享资源而导致的竞态条件和死锁问题,提高程序的稳定性和可靠性
总结
通过上面可知:
推荐的方式当前是智能指针了,智能指针基本介绍如下:
智能指针是C++11标准引入的一种管理动态内存的工具,用于自动管理动态分配的内存,
避免内存泄漏和悬空指针问题。C++11标准提供了三种智能指针:
unique_ptr、shared_ptr和weak_ptr。
shared_ptr允许多个指针指向同一个对象。
unique_ptr独占所指向的对象,尽量使用unique_ptr,资源占用少,效率更高。
weak_ptr是一种弱引用,指向shared_ptr所管理的对象,但不增加引用计数。