内存管理之智能指针一:stl中的auto_ptr智能指针

来源:互联网 发布:java main执行 编辑:程序博客网 时间:2024/06/05 04:19

 一、智能指针作为一种内存管理技术主要为了解决什么问题?(属于个人理解)

1、一般在应用软件的开发过程中,应用程序的代码执行基本上都是通过以下几个步骤来完成:

(1)获取资源(内存、文件句柄、数据库连接等);

(2)执行功能代码;

(3)释放资源;

可能资源的获取相对而言是一个比较容易处理的过程,以内存为例,通过new操作符即可进行内存资源的获得,但是在应用实现的过程中,可能程序员不能保证资源的正确释放,甚至是忘记了调用delete或者是delete[]操作符,导致内存的泄露;有时候也是我们自己无法控制,譬如代码在运行过程中产生异常,退出,那么分配的资源也是无法释放,针对以上种种情况,为了解决资源的正确获取和释放,提出了智能指针来解决该种问题!

可能有时候会利用智能指针来保证线程安全等方面实践!

二、智能指针利用到的技术思想是什么?

(1)利用面向对象的技术,在一个obj的生存期结束的时候会自动调用自己的析构函数,实现内存的资源释放

(2)利用GOF中的proxy(代理模式)的设计思想,利用一个obj来proxy指针的功能,实现和指针完全相同的操作(一般不包括指针的算术运算操作)

因此被称为智能指针,其实在实现层面上更本就不是一个“指针”(pointer),而是一个代理对象,重载了相关的->和*操作符,行为上类似指针。

 

三、STL中的智能指针auto_ptr(释放所有权的智能指针)

1、所在头文件<memory>,内存管理

2、auto_ptr指针概述

auto_ptr是stl(c98标准)库中的唯一一个标准智能指针,主要的目的就是避免相关资源泄露,保证代码的异常安全。

特点是:auot_ptr代理的资源始终都只属于唯一的一个auto_ptr,不能实现资源的共享,即使是在auto_ptr之间进行资源的传递也是如此,因此被称为“释放所有权”。

正式这个特点也是它最主要的一个缺点,虽然可以对资源进行正确的管理,但是对应用人员的要求就比较高了,需要应用人员对这个智能指针的对象的特性比较了解,在使用的过程中,记住相关的特性,才能正确使用,避免出现一些“低级错误”代码。

缺点:在实现上与常规的特性违背了,特别是对于copy construct和assign的操作,在理念上和我们的思想违背了,因为它改变了被拷贝和被赋值者得属性,因此在使用的时候我们必须要把握住它的这个特点,那么才可以正确的使用它。


使用的时候需要注意如下几点:
(1)auto_ptr不能共享所有权
因此在使用auto_ptr的时候不能让两个auto_ptr同时拥有一个资源的指针,那么就会出现资源的重复释放,出现系统级的错误!在这里需要提出一点:最好不要对auto_ptr进行“裸指针”的操作,即使用get()方法,因为这样很危险,代码无法保证,只能由程序员自己去保证。

(2)不存在处理array的auto_ptr指针
因为auto_ptr在析构的时候是使用delete,而不是delete[]


(3)auto_ptr不能满足stl对元素的要求,这个应该是它的一个硬伤
因为auto_ptr的所有权转移的特点,使得它无法满足container的要求在stl中为了满足功能性,在进行元素的操作都要求元素提供copy construct和assign,但是在容器中很多时候都是通过value拷贝的,很少有ref,并且参数大部分都是const ref,因此在对auto_ptr执行copy的时候,满足c98的complier应该都会报错,否则你就惨了。


(4)对于auto_ptr的使用,如果仅仅只是为了保证资源的正确获取和释放
最好使用const auto_ptr obj,这样在进行相互赋值的时候,complier会帮你检查错误。const修饰的对象是obj,只是说自己的所有权是不允许被转移,这属于一种obj feature,因此obj proxy的pointer的value不能改变,但是*pointer的value是可以改变的。

 

(5)在auto_ptr中引入了auto_ptr_ref辅助类,主要是为了解决const的变量作为右值如何变为左值的一个小技巧

大家应该都知道,对于一个函数如果返回一个obj对象,如果不是引用对象,那么就会产生一个临时变脸,在c++标准中对于零时变量,规定为const的右值,但是如果把一个返回auto_ptr的零时变量的函数作为右值,并且赋值给一个auto_ptr变量,例如:

auto_ptr a = function()< return auto_ptr(new int(11))>

因为auto_ptr的copy construct的特性使得它无法使用const auto_ptr作为入参,因此为了解决这个问题,引入了上面的辅助类,在模板技术中重载了相关的类型转换操作符,提供了auto_ptr_ref到auto_ptr的一个construct,这样就通过这种技术实现了const auto_ptr的临时变量到auto_ptr的对象值之间的“拥有权释放”的问题。

 

对于相关技术可以参考stl中的源码!

代码示例说明:

#include <iostream>
#include <memory>

int main( void )
{
    // 创建一个auto_ptr<int> 对象
    std::auto_ptr<int> ptr( new int(11) );
    // 通过重载*操作符实现value提取操作
    if ( ptr.get() )
        std::cout << *ptr << std::endl;

    // 创建另一个对象,实现所有权的转移
    std::auto_ptr<int> cpptr = ptr;
    // 判断所有权是否转移
    if (ptr.get())
        std::cout << "*ptr value = " << *ptr << std::endl;

    if (cpptr.get())
        std::cout << "*cpptr value = " << *cpptr << std::endl;

    return 0;
};

输出结果:可以看到ptr释放了自己的所有权

在实现的过程中利用new操作符开辟了一个新的空间,但是没有使用delete操作符,并不是忘记了

这个正是只能指针的作用,可能通过内置类型无法看到效果,可以自己写一个类,然后再析构函数中输出相关的打印信息,就可以得到相关的验证。

 

关于auto_ptr错误使用的一个例子:

#include <iostream>
#include <memory>

void function( std::auto_ptr<int> ptr )
{
    std::cout << *ptr << std::endl;
}

int main( void )
{
    // 创建一个auto_ptr<int> 对象
    std::auto_ptr<int> ptr( new int(11) );
    // 通过重载*操作符实现value提取操作
    if ( ptr.get() )
        std::cout << *ptr << std::endl;

    function( ptr );

    // 这个会报错,因为auto_ptr在使用的过程中进行了所有权的转移
    // 因此这个new的资源已经在function()函数中释放了,ptr中拥有的
    // 是一个空指针,这个会在运行时报错,如果不报错你就惨了!
    // 应该该写如下:
   
//     if ( ptr.get() )
//         *ptr = 20;
    *ptr = 20;

    return 0;
};

因此在这种情况下只能程序员自己去保证了,complier无法保证这种错误。

其实现在很少使用auto_ptr指针,而主要是使用boost库中的五种智能指针!

 

 

 

原创粉丝点击