1、智能指针
- 智能指针的意义
— 现代C++开发库中最重要的类模板之一
— C++中自动内存管理的主要手段
— 能在很大程度上避开内存相关的问题 - STL中的智能指针
auto_ptr(#include < memory >)
— 生命周期结束时,销毁指向的内存空间
— 不能指向堆数组(只能指向对象或者变量)
— 一片内存空间只属于一个智能指针对象
— 多个智能指针对象不能指向同一片内存空间
程序1:STL中的智能指针 auto_ptr 的 头文件为 #include < memory >
#include <iostream>
#include <string>
#include <memory>
using namespace std;
class Test
{
private:
string m_name;
public:
Test(string name)
{
m_name = name;
cout << "Hello, " << m_name << "." << endl;
}
void print()
{
cout << m_name << endl;
}
~Test()
{
cout<< "Goodbye, " << m_name << "." << endl;
}
};
int main()
{
auto_ptr<Test>t1(new Test("xiebs_"));
t1->print();
cout << t1.get() << endl;
cout << endl;
auto_ptr<Test>t2 = t1;
t2->print();
cout << endl;
cout << t1.get() << endl;
cout << t2.get() << endl;
return 0;
}
分析:这个程序可以看出 STL中的智能指针 auto_ptr 的很强大的功能。
首先,就是智能指针指向一个 Test 类及其初始化:auto_ptr<Test>t1(new Test("xiebs_"))
。
智能指针模板的成员函数还内置一个 get()
函数,可以得到智能指针对象的地址。
生命周期结束时,销毁指向的内存空间。一片内存空间只属于一个智能指针对象。
多个智能指针对象指向同一片内存空间时前面的指针都会被 delete,只最后一个指针指向存空间,这样就避免重复释放的问题。
避免重复释放原理:
Pointer(const Pointer& obj)
{
mp = obj.mp;
const_cast<Pointer&>(obj).mp = NULL;
}
Pointer& operator=(Pointer& obj)
{
if (this != &obj)
{
delete mp;
mp = obj.mp;
const_cast<Pointer&>(obj).mp = NULL;
}
return *this;
}
- STL 中的其它智能指针
— shared_ptr
带有引用计数机制,支持多个指针对象指向同一片内存
— weak_ptr
配合shared_ptr 而引入的一种智能指针
— unique_ptr
一个指针对象指向一片内存空间,不能拷贝构造和赋值
2、QT中的智能指针
— QPointer
1、当其指向的对象被销毁时,它会被自动置空
2、析构时不会自动销毁所指向的对象。
(它的Pointer类里面的析构函数没有delete Pointer类里面成员变量指针指向的Test对象)
#include <QPointer>
#include <QDebug>
class Test:public QObject
{
private:
QString m_name;
public:
Test(QString name)
{
m_name = name;
qDebug() << "Hello, " << m_name;
}
void print()
{
qDebug() << "i'm " << m_name;
}
~Test()
{
qDebug() << "Goodbye " << m_name;
}
};
int main()
{
QPointer<Test> t1(new Test("xiebs"));
QPointer<Test> t2 = t1;
QPointer<Test> t3 = t1;
t1->print();
t2->print();
t3->print();
delete t1;
qDebug() << t1 << endl;
qDebug() << t2 << endl;
qDebug() << t3 << endl;
return 0;
}
分析:对于QT里面内置的智能指针 QPointer,我们可以看出它可允许多个智能指针指向同一个对象,但是当其指向的对象被销毁时,所有的智能指针会被自动置空。析构时不会自动销毁所指向的对象,我们要手动 delete 内存空间。
— QSharedPointer
1、引用计数型智能指针
2、可以被自由的拷贝和赋值
3、当引用计数为0时才删除指向的对象
原理:QSharedPointer这个智能指针指向一个新的对象时,对象对应的引用计数 + 1,当这个指针对象的生命周期结束时,对象所对应的引用计数 -1。如果引用计数为0,就销毁当前对象。
三个智能指针指向一个新的对象时,对象对应的引用计数就是3,当这个指针对象的生命周期结束时,对象所对应的引用计数 从3减到0,于是开始销毁对象,只销毁一次。
#include <QPointer>
#include <QsharedPointer>
#include <QDebug>
class Test:public QObject
{
private:
QString m_name;
public:
Test(QString name)
{
m_name = name;
qDebug() << "Hello, " << m_name;
}
void print()
{
qDebug() << "i'm " << m_name;
}
~Test()
{
qDebug() << "Goodbye " << m_name;
}
};
int main()
{
QPointer<Test> t1(new Test("xiebs"));
QPointer<Test> t2 = t1;
QPointer<Test> t3 = t1;
t1->print();
t2->print();
t3->print();
delete t1;
qDebug() << t1;
qDebug() << t2;
qDebug() << t3 << endl;
QSharedPointer<Test>spt(new Test("zzz"));
QSharedPointer<Test>spt1(spt);
QSharedPointer<Test>spt2(spt);
spt->print();
spt1->print();
spt2->print();
return 0;
}
分析:QSharedPointer 这个智能指针模板相比较QPointer 我个人觉得更好用,毕竟他可以自动析构。原理上面讲了,非常巧妙。
- QT中的其它智能指针
— QWeakPointer
— QScopedPointer
— QScopedArrayPointer
— QSharedDataPointer
— QExplicitlySharedDataPointer
3、创建智能指针类模板
SmartPointer.h
#ifndef SMARTPOINTER_H
#define SMARTPOINTER_H
#include <iostream>
using namespace std;
template <typename T>
class SmartPointer
{
T* mp;
public:
SmartPointer(T* mp = nullptr);
SmartPointer(const SmartPointer<T>& obj);
SmartPointer<T>& operator=(const SmartPointer<T>& obj);
T* operator->();
T& operator*();
T* get();
virtual ~SmartPointer();
};
template <typename T>
SmartPointer<T>::SmartPointer(T* mp)
{
this->mp = mp;
cout << "SmartPointer(T* mp = nullptr);" << endl;
}
template <typename T>
SmartPointer<T>::SmartPointer(const SmartPointer<T>& obj)
{
mp = obj.mp;
const_cast<SmartPointer<T>&>(obj).mp = nullptr;
}
template <typename T>
SmartPointer<T>& SmartPointer<T>::operator=(const SmartPointer<T>& obj)
{
if(this != nullptr)
{
delete mp;
mp = obj.mp;
const_cast<SmartPointer<T>&>(obj).mp = nullptr;
}
return *this;
}
template <typename T>
T* SmartPointer<T>::operator->()
{
return mp;
}
template <typename T>
T& SmartPointer<T>::operator*()
{
return *mp;
}
template <typename T>
T* SmartPointer<T>::get()
{
return mp;
}
template <typename T>
SmartPointer<T>::~SmartPointer()
{
if(mp != nullptr)
{
delete mp;
cout << "~SmartPointer()" << endl;
}
}
#endif // SMARTPOINTER_H
main.cpp
#include <iostream>
#include <string>
#include "SmartPointer.h"
using namespace std;
class Test
{
string m_name;
public:
Test(const char* name)
{
cout << "Hello, " << name << "." << endl;
m_name = name;
}
void print()
{
cout << "I'm " << m_name << "." << endl;
}
~Test()
{
cout << "Goodbye, " << m_name << "." << endl;
}
};
int main()
{
SmartPointer<Test> pt(new Test("xiebs"));
cout << "pt = " << pt.get() << endl;
pt->print();
cout << endl;
SmartPointer<Test> pt1(pt);
cout << "pt = " << pt.get() << endl;
cout << "pt1 = " << pt1.get() << endl;
pt1->print();
return 0;
}
分析:当SmartPointer.h 中的第19行代码和第28行代码const_cast<SmartPointer<T>&>(obj).mp = NULL;
意味着Pointer 这个类没有指向Test对象,里面mp指针指向为空。它就不用delete mp了。
小结:
- 智能指针C++中自动内存管理的主要手段
- 智能指针在各种平台上都有不同的表现形式
- 智能指针能够尽可能的避开内存相关的问题
- STL 和 QT 都提供了对智能指针的支持