C++中auto_ptr智能指针

C++中的auto_ptr(俗称智能指针)所做的事情,使用起来就像普通指针,但当其动态分配内存时,不再需要考虑清理问题。当它的生存期结束时,系统会自动清理它指向的内存。

其实auto_ptr是一个模版类(注意实质上还是一个类)。主要解决内存泄漏问题。

原理:其实就是RAII,在构造的时候获取资源,在析构的时候释放资源,并进行相关指针操作的重载,使用起来就像普通的指针(!!!其实实质上还是一个类)。

0. 先看看如何使用:

int * a=new int(5);
auto_ptr<int> ap(a);//获取某个对象的所有权
cout<<(*ap)<<endl;//之后ap就可以像指针一样使用了。

注意头文件是#include<memory>

注意是auto<int>而不是auto<int *>。观察源代码发现类auto_ptr的私有成员是T* ap;所以这里是<int>而不是<int*>。

最重要的就是理解源码:

template<class T>
class auto_ptr
{
private:
T*ap;
public:
//constructor&destructor-----------------------------------(1)
explicit auto_ptr(T*ptr=0)throw():ap(ptr){}//首先它的构造函数是不支持隐式转换的
~auto_ptr()throw()//虽然构造函数中没有new空间,但是这里使用了delete。是因为智能指针是用来获取指针所有权的,而这个指针是指向new出来的空间的。所以析构需要delete
{
delete ap;
}
//Copy--------------------------------------------(2)
//它的copy有两个函数,注意两个copy函数内部实现,源智能指针将失去对指针的所有权。
auto_ptr(auto_ptr &rhs)throw():ap(rhs.release())//同类型的copy,例如:auto_ptr<int> a(p); auto_ptr<int> b(a);-->就是调用了这个copy
{}
template<class Y>
auto_ptr(auto_ptr<Y>& rhs)throw():ap(rhs.release())//模版中的类型不同的copy。例如:auto_ptr<Derived> a(p); auto_ptr<Base> b(a);用于多态中
{}
//assignment
//和copy类似,源智能指针将失去对指针的所有权。
auto_ptr& operator=(auto_ptr& rhs)throw()
{
reset(rhs.release());
return*this;
}
template<class Y>
auto_ptr& operator=(auto_ptr<Y>& rhs)throw()//参照上面的copy,用于多态中。
{
reset(rhs.release());
return*this;
}
//Dereference----------------------------------------------------(3)
//类auto_ptr重载了这两个操作符,使得它用起来像指针一样。
T&operator*()const throw()
{
return*ap;
}
T*operator->()const throw()
{
return ap;
}
//Helperfunctions------------------------------------------------(4)
//类auto_ptr实现了几个公共函数,提供用户使用
//valueaccess
T* get()const throw()//获取该智能指针拥有的指针
{
return ap;
}
//release ownership
T* release()throw()//释放该智能指针拥有的指针
{
T*tmp(ap);
ap=0;
return tmp;
}
//reset value
void reset(T*ptr=0)throw()//给该智能指针重新获取另一个指针的所有权
{
if(ap!=ptr)
{
delete ap;
ap=ptr;
}
}
//Special conversions-----------------------------------------------(5)
//存在的作用是可以使得下列的式子成立。
//auto_ptr<int> ap=auto_ptr<int>(new int(1));
//auto_ptr<int> ap;
//ap=auto_ptr<int> (new int(1));
template<class Y>
struct auto_ptr_ref
{
Y* yp;
auto_ptr_ref(Y*rhs):yp(rhs){}
};

auto_ptr(auto_ptr_ref<T> rhs)throw():ap(rhs.yp)
{}
auto_ptr& operator=(auto_ptr_ref<T> rhs)throw()
{
reset(rhs.yp);
return*this;
}
template<class Y>
operator auto_ptr_ref<Y>()throw()
{
return auto_ptr_ref<Y>(release());
}
template<class Y>
operator auto_ptr<Y>()throw()
{
return auto_ptr<Y>(release());
}
};

注意的方面:

1. 看看构造函数与析构函数

1> auto的构造时获得对某个对象的所有权。

class A
{
public: A(int i):m_a(i)
              {}
        int m_a;
};
int _tmain(int argc, _TCHAR* argv[])
{
       int * a=new int(5);
       A*a=new A(3);
       auto_ptr<int> ap(a);
       //auto_ptr<int> ap=a;   -----(1) error
       auto_ptr<A>apA=auto_ptr<A>(new A(2));
       //auto_ptr<A> apA=new A(2);  ------(2)         error
       //auto_ptr<A> apA=(auto_ptr<A>)a; ------(3)    error
       system("pause");
       return 0;
}

注意:

前两个错误在于调用了类auto_ptr的copy构造,而很显然没有匹配的copy构造。其实就相当于两个不相干的类的对象进行copy构造,这样显然是不对的。

3错误在于调用了类的赋值重载,其实就相当于两个不相干的类的对象进行赋值操作,这样显然很荒谬。

2>  因为auto_ptr析构会删除内存。所以不要两个auto_ptr拥有同一对象:

       int * a=new int(5);
       auto_ptr<int> ap1(a);
       auto_ptr<int> ap2(a);

这样是很危险。

3> 因为auto_ptr的析构中删除指针用的是delete,而不是delete[].所以我们不能用auto_ptr来管理一个类对象数组。

2. 拷贝和赋值函数

1> 由源码可知,auto_ptr的拷贝和赋值后,源智能指针将失去对指针的所有权。

       int * p=new int(2);
       auto_ptr<int> a(p);
       auto_ptr<int> b(a);
       //cout<<*a<<endl;    error

2> 由于拷贝和赋值的特殊性,当智能指针作为参数对函数进行传参时,就会出现问题,传参的过程中,系统会自动生成一个临时智能指针,实参对其copy构造,则实参就失去了所有权,而函数结束后,系统会销毁这个临时智能指针,所以连同绑定的指针指向的内存都已经被释放,显然不合理。

所以不要把智能指针当作参数。

3> 有源码中可以看到copy和赋值都有两个函数,而第二个函数就是用于多态的。用子类指针对父类指针进行copy构造和赋值。

4> auto_ptr不能作为STL中的容器对象。因为STL容器中的元素要经常copy和赋值,而auto_ptr会传递所有权,不是值语义的。所以不行。

附:值语义就相当于值传递;对象语义就相当于引用传递。

3. auto_ptr提供了一些函数可供使用

get();  release();reset();

4. 说一下特殊转换

//auto_ptr<int> ap=auto_ptr<int>(new int(1));

//auto_ptr<int> ap;

//ap=auto_ptr<int> (new int(1));

如果想使得这两个式子成立,必须要有auto_ptr_ref。

首先:

//auto_ptr<int> ap=auto_ptr<int>(new int(1));

因为auto_ptr<int>(newint(1))是一个临时对象,而临时对象是不能作为copy构造里的引用参数的,所以我们必须重写一个copy构造,使得copy构造的参数不是引用类型。

而我们不能写出这样的copy:auto_ptr(auto_ptr p){};这样显然是不行的,因为传参就会调用copy,则它就会循环调用。所以我们写成:

auto_ptr(auto_ptr_ref<T> rhs)throw():ap(rhs.yp)
{}

之后,我们就要把auto_ptr可以转换成auto_ptr_ref,所以我们写了一个类型转换函数:

template<class Y>
operatorauto_ptr_ref<Y>()throw()
{
returnauto_ptr_ref<Y>(release());
}

这样,我们就可以把那个临时对象转换成auto_ptr_ref,然后再调用我们重写的这个copy构造,我们就实现了这个copy过程。

//auto_ptr<int> ap;

//ap=auto_ptr<int> (new int(1));

而赋值过程和上面的过程是类似的。我们重写赋值函数就可以了。

至此我们用掉用了3个函数。

而auto_ptr_ref里面有4个函数。还有一个:

template<class Y>
operatorauto_ptr<Y>()throw()
{
returnauto_ptr<Y>(release());
}
};

而这个类型转换函数的作用:就是不同模版类型可以相互转换。比如:

template<typename T>
class Base
{
public:
       template<typenameY>
       operator Base<Y>(){
              return Base<Y>();
       }
};

int _tmain(int argc, _TCHAR* argv[])
{
       Base<int> a;
       Base<short> b;
       a=b;//OK
       system("pause");
       return 0;
}

使得a=b;可行。但是具体在auto_ptr中,这个函数具体怎么用,还没有遇到这种情况。

心得:

其实这个auto_ptr就是一个类,只是重载了*和->符号,所以它的对象可以像指针一样:*p来返回引用对象。p->来调用对象的成员。需要注意的是类auto_ptr的实现(重点),比如copy和赋值都跟常理不同。而因为本质上是一个类,所以销毁它是就自动调用了析构函数,使得不会因为异常而内存泄漏。就是RAII技术。

时间: 2024-10-14 08:02:43

C++中auto_ptr智能指针的相关文章

C++中的智能指针(auto_ptr)

实际上auto_ptr 只是C++标准库提供的一个类模板,它与传统的new/delete控制内存相比有一定优势,使用它不必每次都手动调用delete去释放内存.当然有利也有弊,也不是完全完美的. 本文从下面的8个方面来总结auto_ptr使用的大部分内容. 1. auto_ptr是什么? auto_ptr 是C++标准库提供的类模板,auto_ptr对象通过初始化指向由new创建的动态内存,它是这块内存的拥有者,一块内存不能同时被分给两个这样拥有者(auto_ptr).当auto_ptr对象生命

C++中的智能指针

众所周知.C++中对堆内存的申请与释放全然由用户来控制,这就造成用户在使用的时候常常造成内存泄漏.野指针.反复释放等常见的挂掉问题,所以我们有必要提供一套机制.使得用户仅仅需申请对应的内存,不用管释放的问题,事实上这属于著名的RAII(Resource Acquisition Is Initialization)技术 .在C++中这样的技术称作"智能指针",C++中的智能指针技术越来越受到广泛应用.以下简要介绍下智能指针. 从以上描写叙述中能够看出,我们须要提供一套内存显式申请与隐式释

第二讲 auto_ptr智能指针

// STL.cpp : 定义控制台应用程序的入口点. // //智能指针在其生命周期结束后会自动调用delete #include "stdafx.h" #include<iostream> #include<memory> using namespace std; class WebSite { public: WebSite(int x){i = x;cout << i << "调用构造函数" <<

Android系统篇之----Android中的智能指针

一.前言 今天我们开启Android系统篇的文章了,其实一直想弄,只是之前一直没有太多深入的了解,最近又把这块拿出来好好看了一下,所以想从新梳理一下,来看看Android中的这块知识,首先我们今天来看一下:Android中的智能指针的概念,为什么说先看一下智能指针这个知识呢?因为我们在看Android源码的时候,会发现几乎好多地方都用到了这个东东,所以我们在介绍后面的知识点,先来看看这个吧. 二.问题 那么Android中的智能指针是个什么东西呢?我们知道Android用的Java语言开发的,J

Boost中的智能指针(转)

这篇文章主要介绍 boost中的智能指针的使用.(转自:http://www.cnblogs.com/sld666666/archive/2010/12/16/1908265.html) 内存管理是一个比较繁琐的问题,C++中有两个实现方案: 垃圾回收机制和智能指针.垃圾回收机制因为性能等原因不被C++的大佬们推崇, 而智能指针被认为是解决C++内存问题的最优方案. 1. 定义 一个智能指针就是一个C++的对象, 这对象的行为像一个指针,但是它却可以在其不需要的时候自动删除.注意这个“其不需要的

OSG中的智能指针

在OpenSceneGraph中,智能指针(Smart pointer)的概念指的是一种类的模板,它针对某一特定类型的对象(即Referenced类及其派生类)构建,提供了自己的管理模式,以避免因为用户使用new运算符创建对象实例之后,没有及时用delete运算符释放对象,而造成部分内存空间被浪费的后果,也就是所谓的内存泄露错误. 由于OSG中与场景图形有关的大多数类均派生自Referenced类,因此OSG大量使用了智能指针来实现场景图形节点的管理.智能指针的使用为用户提供了一种自动内存释放的

COCOS2D-X中的智能指针

Cocos2d-x中所有内存管理方式的基础是引用计数,动态分配一个Ref对象后其引用计数为1,并通过retain和release来增持和减少其引用计数.引用计数本身并不能帮助我们进行内存管理. 为了正确地释放对象的内存,Cocos2d-x使用Objective-C里面的自动回收池的机制来管理对象内存的释放.Autorelease有点类似于一个共享的"智能指针",该"智能指针"的作用域为一帧,该帧结束后,它将释放自己的引用计数,此时,如果该对象没有被其他"共

ATL和vc++中的智能指针(分别是CComPtr和_com_ptr_t)

一.智能指针的概念 智能指针是一个类,不是指针,智能指针在所包含的指针不再被使用时候会自动释放该所包含指针所占用的系统资源,而不用手动释放. 原理:智能指针封装了包含指针的AddRef()函数和Release()函数,且在该类不被需要的时候在析构函数里调用包含指针的Release()函数释放包含指针的资源.因此实质是利用类的析构达到调用包含指针的Release()函数的目的. 二.VC++中的智能指针:_com_ptr_t _com_ptr_t实质是一个类模板.使用它时需要提供三个参数:接口的名

c++中的智能指针auto_ptr解析

c++中的auto_ptr是一个类,却可以像指针一样去使用.使用auto_ptr需要包含头文件#include <memory> 例如:auto_ptr<string> ps(new string("hello"));可以像指针一样去使用它,可以这样cout << ps->size()<<endl;uto_ptr带来的好处是,程序员并不需要手动的去delete,这给容易忘记delete的程序员带来极大的好处,因为有时候delete真