前言:智能指针auto_ptr(只能指向动态内存)(也是unique_ptr的一种)
auto_ptr是c++标准库的类模板,auto_ptr对象通过初始化指向new创建的动态内存,auto_ptr对象即为这块内存的拥有者,一块内存不能有两个拥有者。
当auto_ptr对象的生命周期结束时,析构函数会将auto_ptr对象拥有的动态内存自动释放,防止内存泄漏。
内存泄漏
解决:
使用方法:
头文件:#include
初始化:
1.构造函数
1>.直接:auto_ptr
2>.用普通指针构造: int *p=new int(22); auto_ptr
2.拷贝构造:用已存在的智能指针构造新的智能指针:
auto_ptr
auto+ptr
对象销毁时,ap_stringnew负责内存的自动销毁。
3.赋值
auto_ptr
auto_ptr
p1=p2; //赋值前,p1指向对象被删除,赋值后,p2不再指向该对象,p1拥有2048这块内存的控制权
4.智能指针作为参数传递很危险:
void *f(auto_ptr
{
cout<<*ap;
}
auto_ptr
f(ap1);
cout<<*ap1 //error,经过f(ap1),由于是值传递,函数作用域中会产生一个临时对象,接收ap1指向的内存,
而在离开该函数f()时,临时对象调析构函数将该内存释放,故ap1不再指向有效内存,访问失败
解决办法:引用或指针,为了防止在函数中对其操作,用const reference作为参数传递:void *f(const auto_ptr
auto_ptr不能被用作容器中:vector
因为进行值传递时,当从函数返回时,容器中的元素会被置位为NULL
5.auto_ptr中常用成员函数
1>get() :返回auto_ptr指向的对象的内存地址
int *p=new int(22);
auto_ptr
cout<
(int所在的那块内存地址)
cout<<&ap1 是ap1对象本身所在的内存地址
2>reset() :重新设置auto_ptr指向的对象
auto_ptr
pstr_auto.reset(new string("love")); //先释放keke的内存空间,再指向love内存空间
3>release() 手动撤销资源:返回auto_ptr指向的对象的内存地址,并释放对这个对象所有权(防止两个对象指向同一地址)
auto_ptr
auto_ptr
auto_ptr
auto_ptr实现关键点:
1.利用:栈上对象在离开作用域时会自动析构
2.编译器比人可靠,析构交给编译器
3.auto_ptr在栈上构建一个对象a,a中封装了动态分配内存的指针p,重载了operator*,operator->,
使对对象a操作其实就是对指针p操作,而在a的析构函数中自动释放p的空间,析构函数是编译器自动调用的。
auto_ptr缺点:
1.不适合于数组,不能大规模使用
2.指针托管权转移:auto_ptr
auto_ptr
auto_ptr不能用于vector的原因:(auto_ptr也不能用于STL算法,如sort,find等)
#include
#include
#include
using namespace std;
class D
{
public:
D():d(1){}
~D(){cout<<"D destruction"<
{
return d;
}
private:
int d;
};
void doNothing(auto_ptr
{
cout<<"donothing"<
}
int main()
{
vector
int i=0;
for(i=0;i<3;i++)
{
auto_vec.push_back(auto_ptr
}
for(i=0;i<3;i++)//get()函数返回智能指针指向的内存空间地址
cout<
//传值(调用拷贝构造函数)
for(i=0;i<3;i++)
doNothing(auto_vec[i]);
for(i=0;i<3;i++)
cout<
auto_vec.clear();
for(i=0;i<3;i++)
auto_vec.push_back(auto_ptr
//赋值(调用auto_ptr类的赋值运算符)
for(i=0;i<3;i++)
auto_ptr
for(i=0;i<3;i++)
cout<
输出结果:
00897F18
00897F78
00897F48
donothing
D destruction //传值后,临时对象超出作用域,析构,地址释放
donothing
D destruction
donothing
D destruction
00000000
00000000
00000000
D destruction //赋值操作,临时对象超出作用域,析构
D destruction
D destruction
00000000
00000000
00000000
请按任意键继续. . .
解决办法:使用shared_ptr
输出:
00897F18
00897F78
00897F48
donothing
D destruction
donothing
D destruction
donothing
D destruction
00000000
00000000
00000000
D destruction
D destruction
D destruction
00000000
00000000
00000000
请按任意键继续. . .
shared_ptr和wak_ptr的原理
共享对象的所有权;初始化一个shared_ptr后,可以使其他shared_ptr实例共享这个对象指向的内存块,
当引用计数为0时,删除内存资源和自身
shared_ptr
shared_ptr
weak_ptr
s1,s2,w1都指向同一个ptr_manage的对象。
shared_ref_cnt和weak_ref_cnt分别指向引用它的shared_ptr和weak_ptr的个数
(在复制构造和赋值时对相应的引用值+1,在析构中对相应的引用值-1即可),ptr_manage中的ptr存放真正的对象指针地址,指向object。
1.当shread_ref_cnt=0时,自动释放ptr指针指向的对象object,ptr=0x00000000,但不释放ptr_manage;
2.当shared_ref_cnt和weak_ref_cnt都为0时,才释放ptr_manage对象;
对象函数原型:
template explicit shared_ptr(T* p);
在ptr_manage对象中,比较重要的几个成员函数包括:
shared_ptr(const shared_ptr & r); //构造函数
void reset();//可以释放该指针,使得对象的引用计数减一;
T* get();//提供直接访问其原始指针的方法,用于向下兼容。
T& operator*() const;//提领操作
T* operator->() const;//指针操作
bool unique() const;//判断是否为唯一拥有对象
long use_count() const;//返回引用计数值
shared_ptr& operator=(const shared_ptr& r );//赋值
weak_ptr:依照上图,weak_ptr与object的生命周期无关,在使用之前很object很可能已经被释放掉,故要先lock。
weak_ptr是为了配合shared_ptr而引入的一种智能指针,它更像是shared_ptr的一个助手而不是智能指针,因为它不具有普通指针的行为,没有重载operator*和->,但可以使用lock获得一个可用的shared_ptr对象,它的最大作用在于协助shared_ptr工作,像旁观者那样观测资源的使用情况.