一:智能指针的发展历史
1、为什么要引入智能指针?
因为存在以下情景:
#include<iostream>
using namespace std;
void F1()
{
int* tmp = new int;
return;//这句代码跳出本函数
delete tmp;//这里并没有得到释放
}
int main()
{
F1();//F1函数中存在内存泄露
return 0;
}
当new 与 delete 配对使用时,在delete的中间有一些譬如break、return、continue、exit之类的语句,程序直接跳出了,那new出来的空间就没有释放,那样就会造成内存泄漏的
因此为了解决类似这样的问题,引入智能指针。
2、智能指针发展阶段
①auto_ptr(管理权的转移)
②scoped_ptr(防拷贝)
③shared_ptr(引用技术)
智能指针采用RAII机制,通过对象来管理指针,构造对象时,完成资源的初始化;析构对象时,对资源进行清理及汕尾.
二:细说三大智能指针
①auto_ptr(管理权的转移)
描述:它是直接把指针交给下一个 具有管理权的指针,在把自身置为NULL
缺陷: 不符合指针的使用,它将原来指向那块儿空间的指针置为NULL。
模拟实现:
class AutoPtr
{
public:
AutoPtr(T* ptr = 0)//构造函数
:_ptr(ptr)
{
ptr = NULL;
}
AutoPtr(AutoPtr<T>& ap)//拷贝构造函数
:_ptr(ap._ptr)
{
ap._ptr = NULL;
}
AutoPtr<T>& operator=(AutoPtr<T>& ap)//赋值运算符重载
{
if (this != &ap)
{
if (_ptr)
{
delete _ptr;
}
_ptr = ap._ptr;
ap._ptr = NULL;
}
return *this;
}
~AutoPtr()//析构函数
{
if (_ptr)
{
delete _ptr;
_ptr = NULL;
}
}
T& operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;
}
private:
T* _ptr;
};
void Test1()
{
AutoPtr<int> ap(new int(1));
AutoPtr<int> ap1(ap);
AutoPtr<int> ap2;
ap2 = ap1;
}
②scoped_ptr(防拷贝)
描述:守卫指针,防止拷贝。
scoped_ptr与auto_ptr类似,但最大的区别就是它不能转让管理权.也就是说,scoped_ptr禁止用户进行拷贝与赋值。即我们将拷贝构造函数与赋值运算符重载的访问限定符设置为private,并且只给出其声明就行了。
缺陷:解决方法太暴力,还是不能同时有两个指针指向同一块儿空间
模拟实现
template<class T>
class ScopedPtr
{
public :
ScopedPtr(T* ptr)//构造函数
:_ptr(ptr)
{}
~ScopedPtr()//析构函数
{
if (NULL != _ptr)
{
delete _ptr;
_ptr = NULL;
}
}
T& operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;
}
private :
ScopedPtr(const ScopedPtr& ap);//拷贝构造函数声明
ScopedPtr& operator=(const ScopedPtr& ap);//赋值运算符重载函数声明
T* _ptr;
};
void TestScopedPtr()
{
ScopedPtr<int> sp1(new int(10));
ScopedPtr<int> sp2(new int(20));
//ScopedPtr<int> sp3(sp1); //错误
//sp1 = sp2 //错误
}
③shared_ptr(引用计数)
描述:在引用计数中,每一个对象负责维护对象所有引用的计数值。当一个新的引用指向对象时,引用计数器就递增,当去掉一个引用时,引用计数就递减。当引用计数到零时,该对象就将释放占有的资源。即:在本例中我们通过count变量来记录当前有多少个对象共同维护着这个指针,每次拷贝/赋值的时候,让count++.
模拟实现
template
class SharedPtr{
public:
//构造函数
SharedPtr(T *ptr=NULL)
:_ptr(ptr)
,_count(NULL){
if(ptr!=NULL){
_count = new int(1);
std::cout<<_ptr<<” Is Created”<
#include<iostream>
#include<memory>
using namespace std;
struct Node
{
shared_ptr<Node> _pre;
shared_ptr<Node> _next;
int data;
~Node()
{
cout << "~Node():" << this << endl;
}
};
void FunTest()
{
shared_ptr<Node> Node1(new Node);
shared_ptr<Node> Node2(new Node);
Node1->_next = Node2;
Node2->_pre = Node1;
cout << "Node1.use_count:" << Node1.use_count() << endl;
cout << "Node2.use_count:" << Node2.use_count() << endl;
}
int main()
{
FunTest();
return 0;
}
运行结果
说明
shared_ptr的使用使得一块空间有两个对象管理,即头个结点的_next域和下一个指针共同管理,或者又头一个指针和第二个结点的_ptr域共同管理所以其_pCount=2,因此同样造成了内存泄露。
weak_ptr的出现就是为了辅助shared_ptr的工作,弥补shared_ptr的不足,解决shared_ptr造成的循环引用问题。
因此将上述代码改成
#include<memory>
#include<iostream>
using namespace std;
struct Node
{
weak_ptr<Node> _pre;
weak_ptr<Node> _next;
int data;
~Node()
{
cout << "~Node():" << this << endl;
}
};
void FunTest()
{
shared_ptr<Node> Node1(new Node);
shared_ptr<Node> Node2(new Node);
Node1->_next = Node2;
Node2->_pre = Node1;
cout <<"Node1.use_count:"<< Node1.use_count() << endl;
cout <<"Node2.use_count:"<< Node2.use_count() << endl;
}
int main()
{
FunTest();
return 0;
}
结果
这样就解决了循环引用的问题,内存就得到了相应的释放。
这里有对比一下C++11与boots库中的,来源:https://blog.csdn.net/zy19940906/article/details/50470087,这是c++11中的智能指针与boost库中的比较,原本boost就是为完善auto_ptr搞得这些,现在c++11有了。