C++智能指针 auto_ptr

C++智能指针 auto_ptr

auto_ptr 是一个轻量级的智能指针, 定义于 memory (非memory.h)中, 命名空间为 std.
auto_ptr 适合用来管理生命周期比较短或者不会被远距离传递的动态对象, 最好是局限于某个函数内部或者是某个类的内部.

使用方法:
  std::auto_ptr<int> pt(new int(10));
  pt.reset(new int(11));

成员函数

  3个重要的函数:
  (1) get 获得内部对象的指针, 由于已经重载了()方法, 因此和直接使用对象是一样的.如 auto_ptr <int> sp(new int(1)); sp 与 sp.get()是等价的
  (2) release 放弃内部对象的所有权,将内部指针置为空, 返回所内部对象的指针, 此指针需要手动释放
    std::auto_ptr<int> ap0(new int(1));
    int* pa = ap0.release();
    delete pa; // 需要手动释放
  (3) reset 销毁内部对象并接受新的对象的所有权(如果使用缺省参数的话,也就是没有任何对象的所有权)

  其构造函数被声明为 explicit, 因此不能使用赋值符对其赋值(即不能使用类似这样的形式 auto_ptr<int> p = new int;)

auto_ptr 的特征

(1) auto_ptr 的对象所有权是独占性的.
  auto_ptr 的拷贝构造和赋值操作符所接受的参数类型都是非const的引用类型(而一般都应该使用的const引用类型), 其原因在于为了使其内部能调用了 release 方法将原有的对象进行释放, 然后使用新对象替换原有的对象.
  因此导致动态对象的所有权被转移了, 新的 auto_ptr 独占了动态对象的所有权. 被拷贝对象在拷贝过程中被修改, 拷贝物与被拷贝物之间是非等价的.
  下面的使用方法将会出错:
    std::auto_ptr<int> pt1(new int(10));
    std::auto_ptr<int> pt2 = pt1;
    printf("pt1:%d\n", pt1); // 此时应输出 0
    printf("pt1 value:%d\n", *pt1); // 错误, 对象已释放
(2) 不能将 auto_ptr 放入到标准容器中. 标准库容器无准备的拷贝行为, 会导致原 auto_ptr 内的对象被释放, 造成难以发觉的错误.

使用 auto_ptr 的注意事项

(1) auto_ptr 不能指向数组
(2) auto_ptr 不能共享所有权
(3) auto_ptr 不能通过复制操作来初始化
(4) auto_ptr 不能放入容器中使用
(5) auto_ptr 不能作为容器的成员
(6) 不能把一个原生指针给两个智能指针对象管理(对所有的智能指针).
  int* p = new int;
  auto_ptr<int> ap1(p);
  auto_ptr<int> ap2(p); // 错误, p不能给第二个智能指针对象. 会引起两次释放p

VC中的源码实现

template<class _Ty>
class auto_ptr
{    // wrap an object pointer to ensure destruction
public:
    typedef auto_ptr<_Ty> _Myt;
    typedef _Ty element_type;

    explicit auto_ptr(_Ty *_Ptr = 0) _THROW0()
        : _Myptr(_Ptr)
    {    // construct from object pointer
    }

    auto_ptr(_Myt& _Right) _THROW0()
        : _Myptr(_Right.release())
    {    // construct by assuming pointer from _Right auto_ptr
    }

    auto_ptr(auto_ptr_ref<_Ty> _Right) _THROW0()
    {    // construct by assuming pointer from _Right auto_ptr_ref
        _Ty *_Ptr = _Right._Ref;
        _Right._Ref = 0;    // release old
        _Myptr = _Ptr;    // reset this
    }

    template<class _Other>
    operator auto_ptr<_Other>() _THROW0()
    {    // convert to compatible auto_ptr
        return (auto_ptr<_Other>(*this));
    }

    template<class _Other>
    operator auto_ptr_ref<_Other>() _THROW0()
    {    // convert to compatible auto_ptr_ref
        _Other *_Cvtptr = _Myptr;    // test implicit conversion
        auto_ptr_ref<_Other> _Ans(_Cvtptr);
        _Myptr = 0;    // pass ownership to auto_ptr_ref
        return (_Ans);
    }

    template<class _Other>
    _Myt& operator=(auto_ptr<_Other>& _Right) _THROW0()
    {    // assign compatible _Right (assume pointer)
        reset(_Right.release());
        return (*this);
    }

    template<class _Other>
    auto_ptr(auto_ptr<_Other>& _Right) _THROW0()
        : _Myptr(_Right.release())
    {    // construct by assuming pointer from _Right
    }

    _Myt& operator=(_Myt& _Right) _THROW0()
    {    // assign compatible _Right (assume pointer)
        reset(_Right.release());
        return (*this);
    }

    _Myt& operator=(auto_ptr_ref<_Ty> _Right) _THROW0()
    {    // assign compatible _Right._Ref (assume pointer)
        _Ty *_Ptr = _Right._Ref;
        _Right._Ref = 0;    // release old
        reset(_Ptr);    // set new
        return (*this);
    }

    ~auto_ptr()
    {    // destroy the object
        delete _Myptr;
    }

    _Ty& operator*() const _THROW0()
    {    // return designated value
#if _ITERATOR_DEBUG_LEVEL == 2
        if (_Myptr == 0)
            _DEBUG_ERROR("auto_ptr not dereferencable");
#endif /* _ITERATOR_DEBUG_LEVEL == 2 */

        return (*get());
    }

    _Ty *operator->() const _THROW0()
    {    // return pointer to class object
#if _ITERATOR_DEBUG_LEVEL == 2
        if (_Myptr == 0)
            _DEBUG_ERROR("auto_ptr not dereferencable");
#endif /* _ITERATOR_DEBUG_LEVEL == 2 */

        return (get());
    }

    _Ty *get() const _THROW0()
    {    // return wrapped pointer
        return (_Myptr);
    }

    _Ty *release() _THROW0()
    {    // return wrapped pointer and give up ownership
        _Ty *_Tmp = _Myptr;
        _Myptr = 0;
        return (_Tmp);
    }

    void reset(_Ty *_Ptr = 0)
    {    // destroy designated object and store new pointer
        if (_Ptr != _Myptr)
            delete _Myptr;
        _Myptr = _Ptr;
    }

private:
    _Ty *_Myptr;    // the wrapped object pointer
};
时间: 2024-10-09 22:01:03

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

智能指针auto_ptr详解

概述:C++中有很多种智能指针,auto_ptr就是其中的一种,该智能指针主要是为了解决"因程序异常退出发生的内存泄漏"这类问题的. 我们先来看下面的问题代码 #include<iostream> #include<memory> #include<exception> using namespace std; //一般指针的处理方式 template<typename T> class OldClass { public: OldCla

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++资源管理以及对[STL]智能指针auto_ptr源码分析,左值与右值

C++:浅谈c++资源管理以及对[STL]智能指针auto_ptr源码分析 by 小威威 1. 知识引入 在C++编程中,动态分配的内存在使用完毕之后一般都要delete(释放),否则就会造成内存泄漏,导致不必要的后果.虽然大多数初学者都会有这样的意识,但是有些却不以为意.我曾问我的同学关于动态内存的分配与释放,他的回答是:"只要保证new和delete成对出现就行了.如果在构造函数中new(动态分配内存),那么在析构函数中delete(释放)就可以避免内存泄漏了!" 事实果真如此么?

【C++智能指针 auto_ptr】

<More Effective C++>ITEM M9中提到了auto_ptr,说是当异常产生的时候,怎么释放为对象分配的堆内存,避免重复编写内存释放语句. PS:这里书里面提到函数退出问题,函数退出会清理栈内存,不管是怎么正常退出还是异常退出(仅有一种例外就是当你调用 longjmp 时.Longjmp 的这个缺点是 C++率先支持异常处理的主要原因).建立在此基础上我们才把对指针的删除操作封装到一个栈对象里面.这样函数退出(异常或是正常)就会调用对象的析构函数,达到我们自动清理所封装指针指

C++智能指针--auto_ptr指针

auto_ptr是C++标准库提供的类模板,头文件<memory>,auto_ptr对象通过初始化指向由new创建的动态内存,它是这块内存的拥有者,一块内存不能同时被分给两个拥有者.当auto_ptr对象生命周期结束时,其析构函数会将auto_ptr对象拥有的动态内存自动释放.即使发生异常,通过异常的栈展开过程也能将动态内存释放.auto_ptr不支持new数组. auto_ptr的出现,主要是为了解决"有异常抛出时发生内存泄漏"的问题.如下的简单代码是这类问题的一个简单示

C++ 智能指针auto_ptr详解

1. auto_ptr 的设计动机: 函数操作经常依照下列模式进行: 获取一些资源 执行一些动作 释放所获取的资源 那么面对这些资源的释放问题就会出现下面的两种情况: 一开始获得的资源被绑定于局部对象,那么当函数退出的时候,这些局部对象的析构函数被自动的调用,从而自动释放掉这些资源; 一开始获得的资源是通过某种显示手段获取,而且并没有绑定在任何对象身上,那么必须以显式的方式释放.这种情况常常发生在指针身上; 例子: 1 void f() 2 { 3 ClassA* ptr = new Class

【C++】智能指针auto_ptr的简单实现

//[C++]智能指针auto_ptr的简单实现 #include <iostream> using namespace std; template <class _Ty> class auto_ptr { public: auto_ptr(_Ty *_P = 0) :_Owns(_Ptr != 0), _Ptr(_P) {} auto_ptr<_Ty>(const auto_ptr <_Ty> &p):_Owns(p._Owns),_Ptr(p.r

智能指针auto_ptr源码剖析

何时我们需要智能指针? 资源所有权的共享 共享所有权是指两个或多个对象需要同时使用第三个对象的情况.这第三个对象应该如何(或者说何时)被释放?为了确保释放的时机是正确的,每个使用这个共享资源的对象必须互相知道对方,才能准确掌握资源的释放时间.从设计或维护的观点来看,这种耦合是不可行的.更好的方法是让这些资源所有者将资源的生存期管理责任委派给一个智能指针.当没有共享者存在时,智能指针就可以安全地释放这个资源了. 要编写异常安全的代码时 异常安全简单地说就是在异常抛出时没有资源泄漏并保证程序状态的一

C/C++——跟我重写智能指针auto_ptr模版类

第一次使用auto_ptr的时候感觉很好用,但是对内部原理根本不懂,心里不知道这东西到底是个什么东东,总是感觉这东东比较陌生.今天有时间来简单实现一下该类模版auto_ptr,实现了该模版类的主要功能,可以让大家了解一下这个东东内部到底是个什么情况. 栈对象和堆对象的区别: 首先,看一下两种类对象的区别,一个是在栈上分配空间,另一个是在堆上分配空间. 如果看到这里,你不清楚堆和栈的区别.那我也不解释了,自行Google..(如果你想baidu也不拦你) 1.先测试栈上分配的对象 #include