您的位置:首页 > 其它

浅析智能指针一

2016-09-04 15:50 169 查看
//  浅析智能指针
  

//  本篇博客主要讲述进来学习C++中关于智能指针的理解

//  何谓智能指针?  所谓智能指针就是智能/自动化的管理指针所指向的动态资源的释放;

//  boost库中和STL库中都有关于智能指针的include文件; 常见的智能指针有:

//  auto_ptr/scoped_ptr/scoped_array/shared_ptr/shared_array 

//  为什么要有智能指针?  因为在实际的代码编写过程中我们稍不注意就会忘记释放动态开辟的资源或者

//忘记关闭打开的空间,造成没必要的资源泄露! 


//例如:

#include<iostream>
#include<cstdio>

using namespace std;

void fun()
{
FILE* pf = fopen("test.txt","w");
if(1)
{
throw 1;//抛出异常
}
if(1)
{
cout<<"fclose"<<endl;//查看是否关闭文件;
fclose(pf);
}

}

int main()
{
try
{
fun();
}
catch(...)//接收异常
{
cout<<"异常"<<endl;
}//程序结束

system("pause");
return 0;
}
//程序结果并没有调用析构函数!!!

//  为什么邀用抛出异常来举例子?   个人认为相比因为代码段太长而忘记释放或者关闭资源,异常处理的时候更是让人防不胜防;  而且后面讲到其他内容的时候也要用到这个例子;

//  正如上述代码所展示的,我们打开了文件却因为抛出异常而没有关闭文件,往往这种事情是很烦人的,所以,智能指针就出现了,专治疑难杂症;

// 这个时候应该知道一件事情:  智能指针的本质,智能指针是通过对象去模仿指针的功能,本质不是指针; 接下来几个智能指针的模拟实现;


//模拟实现 auto_ptr

#include<iostream>

using namespace std;

template<typename T>
class Auto_ptr//转移权限
{
public:
Auto_ptr( T* ptr = 0)//构造函数
:_ptr(ptr)
{}

Auto_ptr(Auto_ptr<T>& sp)//拷贝构造
{
_ptr = sp._ptr ;
sp._ptr = NULL;
}

~Auto_ptr()//析构函数
{
delete _ptr;
}

T* get()
{
return _ptr;
}

Auto_ptr<T>& operator=(const Auto_ptr<T>& sp)//重载赋值运算符
{
delete _ptr;
_ptr = sp._ptr ;
sp._ptr = NULL;

return *this;
}

//为了尽可能的模仿指针,那么指针的基本功能肯定得有;
//例如 *解引用和 ->指向;
T* operator->()//重载->运算符
{
return _ptr;
}

T& operator*()//重载*运算符
{
return *_ptr;
}

private:
T* _ptr;
};

struct A
{
int b;
};

//对智能指针模仿指针的功能进行测试;

void test()
{
// //Auto_ptr<int> p(new int);
//
// /**p.get() = 100;
// *p = 6;*/
// /*cout<<*p.get()<<endl;
// cout<<*p<<endl;*/
//
// /*Auto_ptr <A> p(new A);
// p->b = 6;
// cout<<p->b <<endl;*/

}

int main()
{
system("pause");
return 0;
}

// 我们首先来模拟实现的是auto_ptr; 使用了模板;

// auto_ptr智能指针的特点是 利用权限转移的方法来进行内存的保护;

// 权限转移: 就是内存资源归属权的问题, 对象A本来拥有_ptr所指向空间的使用权_ptr,现在来了个

// 对象B也要使用A的_ptr所指向的空间,那么,好吧,A把他的使用权A._ptr赋给了B._ptr,那么A就没有

// 了使用权,好吧, A._ptr = NULL;  这就是权限转移的本质;即一块空间只能有一个对象拥有使用权。

//  来对内存进行保护!

模拟实现scoped_ptr

//模拟实现scoped_ptr

#include<iostream>

using namespace std;

template<typename T>
class ScopedPtr
{
public:
ScopedPtr (T* ptr)
:_ptr(ptr)
{}
~ScopedPtr ()
{
delete _ptr;
}
T& operator*()
{
retrun *_ptr;
}
T* operator->()
{
return _ptr;
}

protected:
ScopedPtr (const ScopedPtr <T>& sp);
ScopedPtr<T>& operator=(const ScopedPtr<T>& sp);
private:
T* _ptr;
};

int main()
{
return 0;
}


// ScopedPtr和auto_ptr的不同在于,ScopedPtr对成员函数的拷贝构造和赋值运算符的重载

// 进行了保护,直接就写死了不会出现两个一样的对象; 其他成员函数和auto_ptr一样;

//模拟实现scoped_array

#include<iostream>

using namespace std;

template<typename T>
class ScopedArray
{
public:
ScopedArray( T* ptr)
:_ptr(ptr)
{}
~ScopedArray()
{
delete _ptr;
}
T& operator[](int index)
{
return _ptr[index];
}
protected:
ScopedArray (const ScopedArray <T>& sp);
ScopedArray<T>& operator=(const ScopedArray<T>& sp);
private:
T* _ptr;
};
int main()
{
ScopedArray <int> p(new int[5]);

p[2] = 10;
cout<<p[2]<<endl;

system("pause");
return 0;
}

//ScopedArray 就是区别于new和new[] 释放的不同而产生的;

//因为模仿的是数组指针, 那么对于*,和->就不用重载了,只需要对[]进行一个重载;

模拟实现 shared_ptr

//SharedPtr的特点是  采用引用即使的方法对内存进行保护; 引用计数就是类似于写时拷贝的方法;

//关于引用计数和写时拷贝会有专门的博客进行描述,不了解的同学可以自行先了解一下;

#include<iostream>

using namespace std;

template<typename T>
class SharedPtr
{
private:
T* _ptr;
int* _pcount;//引用计数

public:
SharedPtr ( T* ptr)
:_ptr(ptr)
,_pcount(new int(1))
{}

SharedPtr(SharedPtr<T>& sp)
{
_ptr = sp._ptr ;
_pcount = sp._pcount ;
_pcount++;
}

~SharedPtr ()
{
if(--*(_pcount) == 0)
{
delete _ptr;
delete _pcount;
}
}

T& operator*()
{
return *_ptr;
}

T* operator->()
{
return _ptr;
}

//现代的写法:看看和之前的几个智能指针的赋值运算符有什么不同
SharedPtr<T>& operator=(SharedPtr<T> sp)
{
std::swap(_ptr,sp._ptr );
std::swap(_pcount,sp._pcount );
return *this;
}

};

struct A
{
int b;
};

int main()
{
SharedPtr<int> p(new int(2));
SharedPtr <int> q(p);

q = p;

SharedPtr <A> a(new A);
a->b = 4;

//cout<<a->b <<endl;
cout<<*q<<endl;
system("pause");
return 0;
}


模拟实现shared_array

//模拟实现shared_array 数组指针;对[]进行了重载;

#include<iostream>

using namespace std;

template<typename T>
class SharedArray
{
public:
SharedArray ( T* ptr)
:_ptr(ptr)
,_pcount(new int(1))
{}

SharedArray(SharedArray<T>& sp)
{
_ptr = sp._ptr ;
_pcount = sp._pcount ;
_pcount++;
}

~SharedArray ()
{
if(--*(_pcount) == 0)
{
delete _ptr;
delete _pcount;
}
}

T& operator[](int index)
{
return _ptr[index];
}

SharedArray<T>& operator=(SharedArray<T> sp)
{
std::swap(_ptr,sp._ptr );
std::swap(_pcount,sp._pcount );
return *this;
}
private:
T* _ptr;
int* _pcount;
};

int main()
{
SharedArray<int> sp(new int[10]);

sp[1] = 20;

cout<<sp[1]<<endl;

system("pause");
return 0;
}

//  智能指针我们进行了模拟实现,可是一直在说智能指针,它到底只能在哪里?
//  下面我们就要将一个智能指针的应用:  定置删除器;

//  不过在讲删除器之前我们先要说一个概念: 仿函数

// 仿函数: 望文生义,就是模仿函数,就像智能指针一样;模范函数的样子来实现功能,感觉像是在调用函数;

// 举个例子


#include<iostream>

using namespace std;

template<typename T>
struct Equal
{
//注意: 重载()时前往别忘了 operator后面的();
bool operator()(const T& l,const T& r)//重载() ;
{
return l==r;
}
};

int main()
{
Equal<int> equal;

cout<<equal(1,2)<<endl; // 0
cout<<equal(1,1)<<endl; // 1

//是不是达到了模仿函数的功能, 这就是仿函数;
}


//下面,我们就要讲定置删除器了,首先举个例子来体现智能指针的智能:

#include<iostream>
#include<cstdio>

using namespace std;

void fun()
{
FILE* pf = fopen("test.txt","w");
if(1)
{
throw 1;//抛出异常
}
if(1)
{
cout<<"fclose"<<endl;//查看是否关闭文件;
fclose(pf);
}

}

int main()
{
try
{
fun();
}
catch(...)//接收异常
{
cout<<"异常"<<endl;
}//程序结束

system("pause");
return 0;
}

// 这就是我们刚开始讲的那个例子,说好的后面会用到; 现在我们试着用智能指针来解决这个问题

//其中我们用到了boost库,这个boost库需要在网上下载好自己加入路径;

// 例如我的是vs2012 先把boost库复制好,然后找到vs2012的安装路径,打开找到vc,再打开vc找到include文件夹,将boost库复制到include文件夹中即可;  至于使用boost库的方法请看下面的例子;

#include<iostream>
#include<boost\shared_ptr.hpp>
using namespace std;

struct Fclose
{
void operator()(void* ptr)
{
fclose((FILE*)ptr);
}
};

struct Free
{
void operator()(void* ptr)
{
cout<<"free"<<endl;
free(ptr);
}
};

void fun()
{
boost::shared_ptr <FILE> sp(fopen("test.txt","w"),Fclose());
//注意这里是利用了shared_ptr 的第二个参数;

//我们还可以试试malloc开辟的空间用定置删除器
int *p = (int *)malloc(sizeof(int));
boost::shared_ptr <int> sp2(p,Free());

if(1)
{
throw 1;
}
}
int main()
{
try
{
fun();
}
catch(...)//接收异常
{
cout<<"异常"<<endl;
}//程序结束

return 0;
}

//当然讲到这里还没有完,下一篇博客《浅析智能指针2》将会对智能指针的缺陷进行讲述,还有对顶置删除器的模拟实现!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  智能指针