前言
用c++语言开发的一个难点就是指针,但是指针又是最常用的。有时候开辟了一块内存,但是后续使用完忘记释放,这就造成内存的泄露。为了解决这种尴尬的情况,除了长点心:一个new对应一个delete;还有一个办法是使用智能指针。
这里我只稍微说下Qt的常用的智能指针们,和c++11的部分智能指针很像。如果对c++的智能指针很熟悉,这里看一眼就没问题了;若c++基础不扎实,我找了篇c++11智能指针详解,两者可以结合着看。
介绍和示例
智能指针是个类,主要用于管理在堆上分配的内存,它将普通的指针封装为一个栈对象。
QPointer Qt的指针
QPointer所指向的对象必须是QObject或其派生类对象。 因为其对象析构时会执行QObject的析构函数,进而执行QObjectPrivate::clearGuards(this);作用对象被销毁时,自动设置为NULL,这样就不会出现野指针误用的情况了。(注意:写"."和"->"所调用的成员变量是不同的,一个是QPointer对象本身,一个是QPointer指向的指针对象。)
还有就是QPointer是线程不安全的,注意使用场合。
#include <QCoreApplication>
#include <QObject>
#include<QDebug>
#include<QPointer>
#include<QSharedPointer>
#include<QScopedPointer>
class Student:public QObject
{
public:
explicit Student(QObject* parent=nullptr) :QObject(parent)
{
qDebug()<<__FUNCTION__;
}
~Student()
{
qDebug()<<__FUNCTION__;
}
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QPointer<Student> pt=new Student;
delete pt;
qDebug()<<"pt.isNull():"<<pt.isNull()<<"\n";
Student* pt2=new Student;
delete pt2;
if(pt2)
{
qDebug()<<"pt2 is not null";
}
pt2=NULL;
return a.exec();
}
执行结果如下,可以看出若用QPointer释放后,指针直接为空,而普通的指针释放,则不是空,需手动置零。
QSharedPointer共享指针
与 C++中的std::shared_ptr其作用是一样的,是引用计数型的智能指针。使用QSharedPointer时不需要再时刻牢记delete对象以避免内存泄漏, 因为当QSharedPointer超出其作用域时将被销毁;若对象的引用计数为0时, 也将会销毁其封装或指向的对象。
还有一点:QSharedPointer 是线程安全的,因此即使有多个线程同时修改 QSharedPointer 对象也不需要加锁。虽然 QSharedPointer 是线程安全的,但是 QSharedPointer 指向的内存区域可不一定是线程安全的。所以多个线程同时修改 QSharedPointer 指向的数据时还要应该考虑加锁。
QSharedPointer<Student> pt(new Student);
QSharedPointer<Student> pt2=pt;
qDebug()<<" pt.reset();";
pt.reset();
qDebug()<<"pt2.reset()";
pt2.reset();
运行结果如下,可以看出当两个共享指针都不再引用此对象时,被封装的对象被自动释放。
QScopedPointer作用域指针
QScopedPointer和C++中的智能指针std::unique_ptr其概念是一样的,它包装了new操作符在堆上分配的动态对象,能够保证动态创建的对象在任何时候都可以被正确地删除。
QScopedPointer拥有指针的管理权,出了作用域将自动释放删除。 注意这里并不会检查这个对象是否应该删除, 或者是否有其他指针依然引用/指向这个对象, 而是直接删除它.。这也是QScopedPointer和QSharedPointer在自动销毁对象这一作用上的区别。
void test()
{
QScopedPointer<Student> pt(new Student);
}
Student* takeData()
{
QScopedPointer<Student> pt(new Student);
qDebug()<<pt.data();
return pt.take();
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
//超出作用域,释放
test();
//转让管理权
QScopedPointer<Student> pt(takeData());
qDebug()<<pt.data();
pt->sayHello();
return a.exec();
}
运行结果如下,以下演示了超出作用域后的释放,和转移管理权的示例,注意QScopedPointer::data虽然将对象指针给出去了,但是管理权还在QScopedPointer身上。
数组QScopedArrayPointer
因为QScopedPointer的拷贝构造和赋值操作私有的,所以不能用作容器的元素。所以就有了QScopedArrayPointer。这个用法很简单不说了,麻烦。
结束语
c++基础没打好,现在看到一点知识,进行一点学习,加油吧,少年!!