智能指针的由来和基本思想
裸指针:int *p = new int;
,其实就是C风格的指针。
裸指针的缺点:
1.必须手动释放资源,手动调用delete;
2.由于程序逻辑的错误return或者throw异常,导致释放资源的代码delete ptr
没有被调用到;
3.程序运行过程中,发生异常,导致释放资源的代码没有被调用到。
智能指针 : 智能(不管程序运行发生什么意外的情况,一定会帮用户把资源释放掉),不过利用的思想正是对象出作用域,编译器会自动调用对象的析构函数,保证引用的堆空间被正确的释放。
- 数据段:在程序运行结束后,数据段的数据才会被释放;
- 堆: 需要手动调用释放函数释放资源(堆严格意义上也属于数据,上面的数据主要指全局和static对象);
- 栈:** 函数调用结束会自己释放(智能指针基于该思想设计),退出局部作用域,编译器会自动添加销毁局部变量的指令。**
- 自定义局部作用域:
int main(){
int a = 10;
{
std::vector<int> vec;
} //这也是一个局部的作用域,出右括号vec将不存在
}
实现一个智能指针:底层是我们经常使用的裸指针,通过构造函数构造一个栈上的对象,在局部对象出作用域前会自动调用对象的析构函数,即就是释放底层裸指针所引用的外部资源。C++11标准委员会将智能指针从Boost库中引用过来。
实现一个不带引用计数的智能指针:
template <typename T>
class CSmartPtr{
public:
CSmartPtr(T *ptr = NULL)
:mptr(ptr){}
~CSmartPtr(){
delete mptr;
}
T& operator*(){
return *mptr;
}
const T& operator*()const{
return *mptr;
}
T* operator->(){
return mptr;
}
T* operator->()const{
return mptr;
}
private:
T *mptr;
};
class A
{
public:
void func(){ cout << "call A::func" << endl; }
};
//对智能指针的操作最终转成对底层普通指针的操作,当然包括对运算符重载函数的
int main(int argc, char* argv[]){
CSmartPtr <int> ptr1(new int);
*ptr1 = 30;//表面看起来是在解引用智能指针,实际上调用operator*,解引用封装的裸指针
cout << *ptr1 << endl;
CSmartPtr <A> ptr3(new A());
(*ptr3).func();
ptr3->func();//operator->返回的是封装的裸指针,然后裸指针再去调用func
//智能指针对象调用->运算符重载函数返回一个普通指针,普通指针调用对应的方法
const CSmartPtr <A> ptr4(new A());
//(*ptr4).func();
ptr4->func();
return 0;
}