1、智能指针的意义
1.1、
现代C++开发库中最重要的类模板之一
1.2、
C++中
自动内存管理
的主要手段
1.3、
能够在很大程度上
避开内存相关的问题
(如
内存泄漏、内存的多次释放
等)
2、STL中的智能指针
2.1、
auto_ptr智能指针
2.1.1、
生命周期结束时,销毁指向的内存空间
2.1.2、只能用来管理单个动态创建的对象,
而不能管理动态创建的数组。即
不能指向堆数组,只能指向指针堆对象
(变量)
int *pn = new int[100];
auto_ptr<int> ap(pn);//用一个pn初始化ap对象, auto_ptr指向堆数组,释放时,相当于delete pn,而不是delete [],只释放了数组第一个元素,会造成内存泄漏。
2.1.3、一片堆空间
只属于一个
智能指针对象,
多个智能指针对象不能指向同一片堆空间
/*********** auto_ptr使用初探 ********/
#include <iostream>
#include <string>
#include <memory>
using namespace std;
class Test
{
string m_name;
public:
Test()
{
m_name = "DT.SoftWare";
cout << "Hello, " << m_name << "." << endl;
}
Test(const char* name) //字符串常量
{
m_name = name;
cout << "Hello, " << m_name << "." << endl;
}
void print()
{
cout << "I'am, " << m_name << ". " << endl;
}
~Test()
{
cout << "Good Bye, " << m_name << ". " << endl;
}
};
int main()
{
//智能指针,会自动销毁堆空间,即一片堆空间只能属于一个智能指针对象。只能被一个智能指针指向。
//解析意思:auto_ptr这个智能指针类模板<>泛型中是智能指针指向的类型,用一个类地址去初始化智能指针的指向。pt重载了->仔细体会。
auto_ptr<Test> pt(new Test("DT.SoftWare!!")); //pt本质上是一个对象,但是重载了->操作符,就相当于pt对象指向的地址是从堆空间申请来的,string字符串被初始化
cout << "pt = " << pt.get() << endl;//pt指针所指向的内存地址
pt->print();
cout << endl;
//同一个堆空间, 每次只能有一个auto_ptr指针指向它
auto_ptr<Test> pt1(pt); //让pt1指向pt所指向的空间,会发生所有权的转移。
cout << "pt = " << pt.get() << endl; //所有权转移, pt == 0;
cout << "pt1 = " << pt1.get() << endl; //pt1指向原来的堆空间;
//pt->print(); //因为你访问了转换所有权对象指针的私有变量,段错误,成员方法是可以访问的,因为成员方法是对象共享的。
pt1->print();
cout << endl;
//其内部实现的机理。
//auto_ptr<Test> ptArray(new Test[10]); //auto_ptr指向堆数组,会发生内存泄漏,auto_ptr内部实现是当释放时相当于delete ptArray而不是delete[] ptArray
return 0;
}
2.2、其它智能指针
2.2.1、shared_ptr:带有引用计数机制,支持多个指针对象指向同一片内存
2.2.2、weak_ptr: 配合shared_ptr而引入的一种智能指针来协助shared_ptr工作,它可以从一个shared_ptr或者另一个weak_ptr对象构造,获得资源的观测权。但weak_ptr不能直接访问资源,它的构造和析构不会引起指针引用计数的增加或减少。
2.2.3、unique_ptr:是auto_ptr的进化版,也是一个指针对象指向一片内存空间,但不能拷贝构造和赋值。
3、Qt中的智能指针
3.1、QPointer
3.1.1、当其指向的对象被销毁时,这个指针会被自动置空。
3.1.2、析构时不会自动销毁所指向的对象
3.1.3、这种指针主要是用来解决手动释放对象时造成的多次释放的问题。因为当删除一个对象时,所有指向该对象的QPointer指针都会被置空。
3.2、QSharedPointer
3.2.1、引用计数型智能指针
3.2.2、可以被自由地拷贝和赋值
3.2.3、当引用计数为0时才删除指向的对象,即会自动释放所指向的对象。
#include <QPointer>
#include <QSharedPointer>
#include <QDebug>
class Test:public QObject
{
QString m_name;
public:
Test(const char* name)
{
m_name = name;
qDebug() << "Hello, " << m_name << ".";
}
void print()
{
qDebug()<< "Good bye11" << m_name << ".";
}
~Test()
{
qDebug() << "Good bye" << m_name << ".";
}
};
int main()
{
QPointer<Test> pt(new Test("DT.SoftWare!"));//pt = new Test("DT.SoftWare!")
QPointer<Test> pt1 = pt; //所有权不会转让,与pt指向同一个堆空间
QPointer<Test> pt2(pt); //所有权不会转让,与pt指向同一个堆空间
pt->print();
pt1->print();
pt2->print();
delete pt; //删除一个对象时,pt,pt1,pt2会同时被置空。注意,任意删除一个,这个QPointer智能指针的最大特色。
qDebug()<< "pt = " << pt;
qDebug()<< "pt1 = " << pt1;
qDebug()<< "pt2 = " << pt2;
qDebug()<<endl;
//带有引用计数
QSharedPointer<Test> spt(new Test("Demo"));
QSharedPointer<Test> spt1(spt);
QSharedPointer<Test> spt2(spt);
spt->print();
spt1->print();
spt2->print();
spt.clear();
spt1.clear();
//spt2.clear();
qDebug()<< "spt = " << spt;
qDebug()<< "spt1 = " << spt1;
qDebug()<< "spt2 = " << spt2;
//spt->print();//错误,不能使用已经释放的对象。
return 0;
}
3.3、QT中的其它智能指针
3.3.1、①QWeakPointer;②QScopedPointer③QScopedArrayPointer;④QSharedDataPointer;⑤QExplicitlySharedDataPointer
4、自定义的智能指针类模板
编程智能指针类模板1(仿auto_ptr)
#ifndef _SMARTPOINTER_H_
#define _SMARTPOINTER_H_
#include <iostream>
using namespace std;
//仿auto_ptr:同一堆空间对象只能有一个智能指针指向。
/*
创建智能指针类模板的步骤:
1类中创建一个成员变量,为模板类的类型,
2构造函数中初始化这个类的指向。
3定义拷贝构造函数。
4重载赋值操作符,4要素
5重载-> *操作符。返回智能指针指向的类对象。
*/
template<typename T>
class SmartPointer
{
T* mp;
public:
SmartPointer(T* p = NULL)//构造函数(T* p = NULL)这是默认类型。
{
mp = p;
}
//拷贝构造函数
SmartPointer(const SmartPointer<T>& obj) //类的引用
{cout << "saf拷贝构造函数f" << endl;
mp = obj.mp; //堆空间的所有权转让
//去掉const属性,obj放弃所有权,同时自己置空。
const_cast<SmartPointer<T>&>(obj).mp = NULL;
}
//重载赋值操作符
SmartPointer<T>& operator=(const SmartPointer<T>& obj)
{cout << "saf重载赋值操作符f" << endl;
if(this != &obj)//避免自赋值
{
delete mp; //删除原先指向的堆空间
mp = obj.mp;//obj转让堆空间所有权
const_cast<SmartPointer<T>&>(obj).mp = NULL; //类的地址
}
return *this;
}
//重载->操作符
T* operator->()
{
return mp;//返回指向对象的指针。
}
//重载解引用操作符*
T& operator*()
{
return *mp;
}
//判断所指向堆空间是否为NULL
bool isNULL()
{
return (mp == NULL);
}
//返回对象的堆空间指针(仿auto_ptr智能指针)
T* get()
{
return mp;
}
~SmartPointer()
{
delete mp;
}
};
#endif
#include <iostream>
#include <string>
#include "test.h"
using namespace std;
class Test
{
string m_name;
public:
Test()
{
m_name = "DT.SoftWate!";
cout << "Hello, " << m_name << "." << endl;
}
Test(const char* name)
{
m_name = name;
cout << "Helllo, " << m_name << "." << endl;
}
void print()
{
cout << "I'm" << m_name << "." << endl;
}
~Test()
{
cout << "Good bye, " << m_name << "." << endl;
}
};
int main()
{
//本质上智能指针是个对象(而不是指针,只是重载了->操作符)
SmartPointer<Test> pt(new Test("DT>Software!!"));
cout << "pt = " << pt.get() << endl; //获得pt指向的堆空间
pt->print();
cout << endl;
SmartPointer<Test> pt1(pt); //转让所有权//pt1是智能指针类的对象。
cout << "pt = " << pt.get() << endl;//为0NULL,说明转让了。
cout << "pt1 = " << pt1.get() << endl;
pt1->print();
return 0;
}
创建智能指针类模板2(仿sharead_ptr)
#ifndef _SMARTPOINTER_H
#define _SMARTPOINTER_H
#include <iostream>
//引用计数类
class SmartCount
{
int useCount; //计数变量
public:
SmartCount(int c):useCount(c)
{
}
~SmartCount()
{
}
//增加引用计数
int addRef()
{
return ++useCount;
}
//减少引用计数
int release()
{
return --useCount;
}
//获取当前引用次数
int getCount()
{
return useCount;
}
};
//具有引用计数功能的智能指针类
template<typename T>
class SmartPointer
{
T* m_pointer;
SmartCount* m_pSmartCount; //计数类
public:
//构造空指针(形如SmartPointer<int> pi的空指针时)
explicit SmartPointer();
//构造函数
SmartPointer(const T* pointer);
//拷贝构造函数
SmartPointer(const SmartPointer<T>& obj);
//析构函数
~SmartPointer();
//重载指针操作符->
T* operator->();
//重载解引用操作符
T& operator*();
//重载赋值操作符//SmartPointer<Test>&返回引用也是可以的
void operator=(const SmartPointer<T>& obj); //返回的不是引用吗?
//重载相等判断操作符
bool operator==(const SmartPointer<T>& obj);
};
//构造空指针(形如SmartPointer<int> pi的空指针时)
template <typename T>
SmartPointer<T>::SmartPointer():m_pointer(NULL),m_pSmartCount(NULL)
{
//无参构造函数初始化列表
}
//构造函数(当创建形如SmartPointer<int> pi(new int)或
// SmartPointer<int> pi=new int)
template <typename T>
SmartPointer<T>::SmartPointer(const T* pointer)
{
m_pointer = const_cast<T*>(pointer); //去const属性
m_pSmartCount = new SmartCount(1); //给useCount赋值为1
}
//拷贝构造函数
template <typename T>
SmartPointer<T>::SmartPointer(const SmartPointer<T>& obj)
{
m_pointer = obj.m_pointer;
m_pSmartCount = obj.m_pSmartCount;
if(m_pSmartCount)
{
m_pSmartCount->addRef(); //调用这个方法,增加1 计数。
}
}
//析构函数
template <typename T>
SmartPointer<T>::~SmartPointer()
{
if(m_pointer && m_pSmartCount->release()<= 0)
{
delete m_pointer;
delete m_pSmartCount;
m_pointer = NULL;
}
}
//重载指针操作符->
template <typename T>
T* SmartPointer<T>::operator->()
{
return m_pointer;
}
//重载解引用操作符
template <typename T>
T& SmartPointer<T>::operator*()
{
return *m_pointer;
}
//重载赋值操作符
template <typename T>
void SmartPointer<T>::operator=(const SmartPointer<T>& obj)//SmartPointer<Test>&
返回引用也是可以的
{
//判断旧对象是否可删除(如果引用计数release仍大于0,说明
// 原来的堆空间被其它对象所引用,就不删除旧的堆空间,
// 留给那个引用它的对象去删除)
if(m_pointer && m_pSmartCount->release()<= 0)
{
delete m_pointer;
delete m_pSmartCount;
m_pointer = NULL;
}
m_pointer = obj.m_pointer;
m_pSmartCount = obj.m_pSmartCount;
//增加新对象的引用计数
if(m_pSmartCount)
m_pSmartCount->addRef();
}
//重载相等判断操作符
template <typename T>
bool SmartPointer<T>::operator==(const SmartPointer<T>& obj)
{
return m_pointer == obj.m_pointer;//本身对象的指针和要比对的对象的指针是否相同。
}
#endif
#include <iostream>
#include <string>
#include "SmartPointer.h"
using namespace std;
class Test
{
string m_name;
public:
Test()
{
m_name = "DT_SoftWare!!";
cout << "Hello, " << m_name << ". " << endl;
}
Test(const char* name)
{
m_name = name;
cout << "Hello" << m_name << ". " << endl;
}
void print()
{
cout << "I'm" << m_name << ". " << endl;
}
~Test()
{
cout << "Goodbye , " << m_name << ". " << endl;
}
};
int main()
{
//本质上智能指针是个对象(而不是指针,只是重载了->操作符)
SmartPointer<int> pi = new int(5);//pi指向的地址上面是5。
SmartPointer<float> pf(new float(10.0f));
cout <<"*pi=" << *pi <<", *pf="<<*pf<<endl;
SmartPointer<Test> pt(new Test("SantaClaus")); //pt = new Test("SantaClaus")
pt->print();
SmartPointer<Test> ppt(pt); //指向同一片内存空间 ,,赋值的效果。
if (ppt == pt)
cout <<"ppt == pt" << endl;
return 0;
}
5、小结
5.1、智能指针是C++中自动内存管理的主要手段
5.2、智能指针在各种平台上都有不同的表现形式
5.3、智能指针能够尽可能的避开内存相关的问题
5.4、STL和Qt中提供了对智能指针的支持