`
lobin
  • 浏览: 418067 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

C++ auto_ptr

 
阅读更多

auto_ptr

C++中的一种智能指针实现,auto_ptr被定义为一个模板类。C++11中已经废弃了。

 

auto_ptr定义如下:

template<class X>
class auto_ptr
{
public:
    typedef X element_type;

    explicit auto_ptr(X* p =0) throw();
    auto_ptr(auto_ptr&) throw();
    template<class Y> auto_ptr(auto_ptr<Y>&) throw();
    auto_ptr& operator=(auto_ptr&) throw();
    template<class Y> auto_ptr& operator=(auto_ptr<Y>&) throw();
    auto_ptr& operator=(auto_ptr_ref<X> r) throw();
    ~auto_ptr() throw();

    typename add_lvalue_reference<X>::type operator*() const throw();
    X* operator->() const throw();
    X* get() const throw();
    X* release() throw();
    void reset(X* p =0) throw();

    auto_ptr(auto_ptr_ref<X>) throw();
    template<class Y> operator auto_ptr_ref<Y>() throw();
    template<class Y> operator auto_ptr<Y>() throw();
};

 

构造

auto_ptr的构造除了特殊的拷贝构造函数,提供了两种构造,一个是直接通过一个对象指针来构造auto_ptr,另一个是通过一个auto_ptr_ref来构造auto_ptr。

 

 

直接通过对象指针构造

explicit auto_ptr(X* p =0) throw();

 

传入一个指针构造一个auto_ptr,传入的指针参数类型由类模板参数决定,这里指定了一个默认值。需要注意的是,这个构造函数指定了“ explicit”。

 

参考下面的实现,这种构造方式仅仅是将一个对象指针赋值给auto_ptr内部维护的_M_ptr,auto_ptr通过它对指针进行管理。 

explicit auto_ptr(element_type* __p = 0) throw() : _M_ptr(__p) { }

传给__p的对象指针必须是通过new创建。

 

构造示例

这种形式的构造最简单的就是:

std::auto_ptr<int> p;

 

int *i = new int(100);

std::auto_ptr<int> p(i);

 

因为这种构造函数形式指定了“ explicit”,所以不能写成以下形式:

int *i = new int(100);

std::auto_ptr<int> p = i;

 

通过auto_ptr_ref构造

auto_ptr(auto_ptr_ref<X>) throw();

这通过一个auto_ptr_ref(auto_ptr引用)构造一个auto_ptr。

auto_ptr(auto_ptr_ref<element_type> __ref) throw() : _M_ptr(__ref._M_ptr) { }

 

拷贝构造

auto_ptr(auto_ptr&) throw();

这是一个拷贝构造

auto_ptr(auto_ptr& __a) throw() : _M_ptr(__a.release()) { }

 

template<class Y> auto_ptr(auto_ptr<Y>&) throw();

这也是一个拷贝构造,但这个构造是一个模板方法,实现和上面的拷贝构造其实是一样的。

template<typename _Tp1> auto_ptr(auto_ptr<_Tp1>& __a) throw() : _M_ptr(__a.release()) { }

 

析构

析构的时候只是简单的销毁这个指针指向的对象。

~auto_ptr() { delete _M_ptr; }

 

操作符重载

重载*(指针)操作符

typename add_lvalue_reference<X>::type operator*() const throw();

 

通过*操作符可以解引用访问到指向的对象,如*p。

 

重载->操作符

X* operator->() const throw();

 

通过->操作符可以将一个auto_ptr变量当成一个指针,进而访问对象成员,这用于类,结构体等类型。

 

重载=操作符

有3中定义:

auto_ptr& operator=(auto_ptr&) throw();

将一个auto_ptr赋值给另一个auto_ptr。

 

template<class Y> auto_ptr& operator=(auto_ptr<Y>&) throw();

将一个auto_ptr<Y>类型赋值给auto_ptr。

 

auto_ptr& operator=(auto_ptr_ref<X> r) throw();

将一个auto_ptr_ref赋值给auto_ptr。

 

还有两个看似操作符重载的用于隐式转换函数,这是一种“conversion function”,即类型“转换函数”。

 

template<class Y> operator auto_ptr_ref<Y>() throw();

将一个auto_ptr类型隐式转换为auto_ptr_ref<Y>类型

 

template<class Y> operator auto_ptr<Y>() throw();

将一个auto_ptr类型隐式转换为auto_ptr<Y>类型

 

写道
Type conversions of class objects can be specified by constructors and by conversion functions. These conversions are called user-defined conversions and are used for implicit type conversions (Clause 4), for initialization (8.5), and for explicit type conversions (5.4, 5.2.9).

 

 

这种操作符重载来实现隐式转换不多见,这个也许用来模拟实现装箱/拆箱或许不错,必须将char、int、long、float、double对应的Char、Integer、Long、Float、Double的class类型对象通过这种隐式类型转换为对应的char、int、long、float、double类型,是一个很巧妙的设计以实现拆箱效果。实际到底是否需要这么做还得结合实际商榷。不管怎么说,这里来个这样的示例:

 

class Integer
{
private:
  int v;
public:
  Integer(int _v) : v(_v) { }
};

在上面的例子中,定义了一个int类型对应的类Integer,我们可以通过一个int参数构造一个Integer对象,如下:

Integer i(1);

 

但上面的代码不能将一个Integer对象转换为int类型,如下:

int _i = i;

要实现以上的转换,可以通过操作符重载来实现隐式转换

  operator int()
  {
    return v;
  }

这样就可以实现将一个Integer对象转换为int类型。

int _i = i;

实际上就调用了operator int()重载函数来实现隐式转换以达到拆箱效果,上面的代码等同于:

int _i = i.operator int();

 

 

release

释放(release)并不会销毁维护的这个指针指向的对象。只是将维护的这个指针置为0,也就是设置为NULL。释放(release)之后不能在通过这个auto_ptr去操作这个指针指向的对象。但返回的时候会返回原先维护的这个指针,这个指针还有效,这个指针指向的对象并没有被销毁。

      element_type*
      release() throw()
      {
	element_type* __tmp = _M_ptr;
	_M_ptr = 0;
	return __tmp;
      }

在上面的构造示例中,可以根据release的返回值重新构造一个auto_ptr,如下:

std::auto_ptr<int> p2(p.release());

这个时候就不能再通过p来操作维护的这个指针指向的对象,但可以通过p2来操作维护的这个指针指向的对象。

 

auto_ptr_ref

在构造auto_ptr的时候可以通过一个auto_ptr_ref(auto_ptr引用)来构造一个auto_ptr。

template <class Y> struct auto_ptr_ref {};

这个引用实际并不会直接构造。我们可以直接将一个auto_ptr变量赋值给auto_ptr_ref变量,这里可以通过__ptr_访问到引用的对象指针。如下:

int *i = new int(100);

std::auto_ptr<int> p(i);

std::auto_ptr_ref<int> p_ref = p;

 

这实际上用到操作符auto_ptr_ref<Y>重载:

template<class Y> operator auto_ptr_ref<Y>() throw();

注意这里会释放(release)掉p引用的指针,这意味着不能再使用p。

 

具体定义如下:

template <class _Tp>
struct auto_ptr_ref
{
    _Tp* __ptr_;
};

 

参考libstdc++-v3/include/backward/auto_ptr.h

  template<typename _Tp>
    class auto_ptr
    {
    private:
      _Tp* _M_ptr;
      
    public:
      /// The pointed-to type.
      typedef _Tp element_type;
      
      /**
       *  @brief  An %auto_ptr is usually constructed from a raw pointer.
       *  @param  __p  A pointer (defaults to NULL).
       *
       *  This object now @e owns the object pointed to by @a __p.
       */
      explicit
      auto_ptr(element_type* __p = 0) throw() : _M_ptr(__p) { }

      /**
       *  @brief  An %auto_ptr can be constructed from another %auto_ptr.
       *  @param  __a  Another %auto_ptr of the same type.
       *
       *  This object now @e owns the object previously owned by @a __a,
       *  which has given up ownership.
       */
      auto_ptr(auto_ptr& __a) throw() : _M_ptr(__a.release()) { }

      /**
       *  @brief  An %auto_ptr can be constructed from another %auto_ptr.
       *  @param  __a  Another %auto_ptr of a different but related type.
       *
       *  A pointer-to-Tp1 must be convertible to a
       *  pointer-to-Tp/element_type.
       *
       *  This object now @e owns the object previously owned by @a __a,
       *  which has given up ownership.
       */
      template<typename _Tp1>
        auto_ptr(auto_ptr<_Tp1>& __a) throw() : _M_ptr(__a.release()) { }

      /**
       *  @brief  %auto_ptr assignment operator.
       *  @param  __a  Another %auto_ptr of the same type.
       *
       *  This object now @e owns the object previously owned by @a __a,
       *  which has given up ownership.  The object that this one @e
       *  used to own and track has been deleted.
       */
      auto_ptr&
      operator=(auto_ptr& __a) throw()
      {
	reset(__a.release());
	return *this;
      }

      /**
       *  @brief  %auto_ptr assignment operator.
       *  @param  __a  Another %auto_ptr of a different but related type.
       *
       *  A pointer-to-Tp1 must be convertible to a pointer-to-Tp/element_type.
       *
       *  This object now @e owns the object previously owned by @a __a,
       *  which has given up ownership.  The object that this one @e
       *  used to own and track has been deleted.
       */
      template<typename _Tp1>
        auto_ptr&
        operator=(auto_ptr<_Tp1>& __a) throw()
        {
	  reset(__a.release());
	  return *this;
	}

      /**
       *  When the %auto_ptr goes out of scope, the object it owns is
       *  deleted.  If it no longer owns anything (i.e., @c get() is
       *  @c NULL), then this has no effect.
       *
       *  The C++ standard says there is supposed to be an empty throw
       *  specification here, but omitting it is standard conforming.  Its
       *  presence can be detected only if _Tp::~_Tp() throws, but this is
       *  prohibited.  [17.4.3.6]/2
       */
      ~auto_ptr() { delete _M_ptr; }
      
      /**
       *  @brief  Smart pointer dereferencing.
       *
       *  If this %auto_ptr no longer owns anything, then this
       *  operation will crash.  (For a smart pointer, <em>no longer owns
       *  anything</em> is the same as being a null pointer, and you know
       *  what happens when you dereference one of those...)
       */
      element_type&
      operator*() const throw() 
      {
	__glibcxx_assert(_M_ptr != 0);
	return *_M_ptr; 
      }
      
      /**
       *  @brief  Smart pointer dereferencing.
       *
       *  This returns the pointer itself, which the language then will
       *  automatically cause to be dereferenced.
       */
      element_type*
      operator->() const throw() 
      {
	__glibcxx_assert(_M_ptr != 0);
	return _M_ptr; 
      }
      
      /**
       *  @brief  Bypassing the smart pointer.
       *  @return  The raw pointer being managed.
       *
       *  You can get a copy of the pointer that this object owns, for
       *  situations such as passing to a function which only accepts
       *  a raw pointer.
       *
       *  @note  This %auto_ptr still owns the memory.
       */
      element_type*
      get() const throw() { return _M_ptr; }
      
      /**
       *  @brief  Bypassing the smart pointer.
       *  @return  The raw pointer being managed.
       *
       *  You can get a copy of the pointer that this object owns, for
       *  situations such as passing to a function which only accepts
       *  a raw pointer.
       *
       *  @note  This %auto_ptr no longer owns the memory.  When this object
       *  goes out of scope, nothing will happen.
       */
      element_type*
      release() throw()
      {
	element_type* __tmp = _M_ptr;
	_M_ptr = 0;
	return __tmp;
      }
      
      /**
       *  @brief  Forcibly deletes the managed object.
       *  @param  __p  A pointer (defaults to NULL).
       *
       *  This object now @e owns the object pointed to by @a __p.  The
       *  previous object has been deleted.
       */
      void
      reset(element_type* __p = 0) throw()
      {
	if (__p != _M_ptr)
	  {
	    delete _M_ptr;
	    _M_ptr = __p;
	  }
      }
      
      /** 
       *  @brief  Automatic conversions
       *
       *  These operations are supposed to convert an %auto_ptr into and from
       *  an auto_ptr_ref automatically as needed.  This would allow
       *  constructs such as
       *  @code
       *    auto_ptr<Derived>  func_returning_auto_ptr(.....);
       *    ...
       *    auto_ptr<Base> ptr = func_returning_auto_ptr(.....);
       *  @endcode
       *
       *  But it doesn't work, and won't be fixed. For further details see
       *  http://cplusplus.github.io/LWG/lwg-closed.html#463
       */
      auto_ptr(auto_ptr_ref<element_type> __ref) throw()
      : _M_ptr(__ref._M_ptr) { }
      
      auto_ptr&
      operator=(auto_ptr_ref<element_type> __ref) throw()
      {
	if (__ref._M_ptr != this->get())
	  {
	    delete _M_ptr;
	    _M_ptr = __ref._M_ptr;
	  }
	return *this;
      }
      
      template<typename _Tp1>
        operator auto_ptr_ref<_Tp1>() throw()
        { return auto_ptr_ref<_Tp1>(this->release()); }

      template<typename _Tp1>
        operator auto_ptr<_Tp1>() throw()
        { return auto_ptr<_Tp1>(this->release()); }
    } _GLIBCXX11_DEPRECATED_SUGGEST("std::unique_ptr");

 

 

示例,在下面的例子中,在main函数返回时,指针变量i指向的new申请的内存将被自动释放,因为在main函数返回时会隐式调用p的析构函数,auto_ptr的析构函数会负责将维护的这个指针指向的对象内存释放。

#include <iostream>
#include <memory>

int main()
{
  int *i = new int(100);
  std::auto_ptr<int> p(i);

  std::cout<<"i="<<*p<<std::endl;
  return 0;
}

 

分享到:
评论

相关推荐

    C++ unique_ptr weak_ptr shared_ptr auto_ptr智能指针.doc

    在 C++ 中,有四种智能指针:auto_ptr、unique_ptr、shared_ptr 和 weak_ptr,每种智能指针都有其特点和使用场景。 一、auto_ptr auto_ptr 是 C++98 中引入的智能指针,它可以自动释放动态分配的内存。但是,auto_...

    C++ auto_ptr源码

    该文档是C++ auto_ptr源码,感兴趣的可以自行下载学习。

    自动指针auto_ptr

    详细讨论c++ auoto_ptr的原型,用法,以及注意事项

    自己实现的auto_ptr

    标题中的“自己实现的auto_ptr”指的是用户自行编写的一个智能指针类,模仿了C++标准库中的`std::auto_ptr`。`std::auto_ptr`是C++标准库中的一个智能指针,用于管理动态分配的对象,它会在适当的时候自动删除所指向...

    auto_ptr指针介绍(智能指针).

    尽管在C++11及以后版本中引入了更强大的智能指针如`unique_ptr`和`shared_ptr`,但了解`auto_ptr`的基本概念和用法对于理解智能指针仍然非常重要。 #### `auto_ptr`的概念与作用 `auto_ptr`主要用来管理动态分配的...

    auto_ptr再回忆

    标题与描述均提到“auto_ptr再回忆”,暗示文章将通过一个故事的形式,回顾与探讨C++中`auto_ptr`的使用及其潜在问题。`auto_ptr`是C++标准库中的一个智能指针类,用于自动管理动态分配的资源,当`auto_ptr`对象超出...

    unique_ptr源码

    该文档是C++ auto_ptr源码,感兴趣的可以自行下载学习,方便大家学习参考。

    c++的智能指针Auto_PTR的细致而经典的分析

    ### C++ 智能指针 Auto_PTR 的细致而经典分析 #### 一、引言 C++ 是一门强大而灵活的语言,它不仅为开发者提供了底层控制能力,还通过多种高级特性来帮助开发者提高代码质量和可维护性。其中一项重要的功能就是...

    C++中的auto_ptr智能指针的作用及使用方法详解

    在C++11之后,`auto_ptr`已被`unique_ptr`取代,因为`auto_ptr`有一些限制和潜在的问题,但在理解C++的历史和发展时,学习`auto_ptr`仍然是有价值的。 **1. `auto_ptr`的基本概念** `auto_ptr`是一个类模板,它包装...

    C++中auto_ptr智能指针的用法详解

    其中,`auto_ptr`是C++98标准库中提供的一个智能指针类型,但在C++11及更高版本中已被推荐弃用,取而代之的是`unique_ptr`。尽管如此,理解`auto_ptr`的工作原理仍然是学习C++历史和理解智能指针概念的重要部分。 `...

    C++智能指针:auto-ptr详解.pdf

    本文将深入探讨C++中的`auto_ptr`,一种早期的智能指针,尽管在C++11标准中已被`unique_ptr`取代,但它仍然是理解智能指针工作原理的良好起点。 智能指针的基础原理在于,它是一个类,能够通过构造函数绑定到一个...

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

    实际上auto_ptr 仅仅是C++标准库提供的一个类模板,它与传统的new/delete控制内存相比有一定优势。使用它不必每次都手动调用delete去释放内存。当然有利也有弊,也不是全然完美的。  本文从以下的8个方面来总结...

    C++11智能指针之weak_ptr详解

    `shared_ptr`是C++11中引入的智能指针之一,它使用引用计数来跟踪指向同一对象的指针数量。当引用计数减少到零时,`shared_ptr`会自动删除所指向的对象。然而,当两个`shared_ptr`相互引用形成循环引用时,它们的...

    暗黑风格-C++八股文-v1.0.pdf

    - `auto_ptr` 是在C++98标准中引入的,但在C++11之后被废弃。它的设计理念是实现所有权转移,即一个`auto_ptr`实例拥有对动态分配对象的所有权,当`auto_ptr`对象离开作用域时,它会自动删除所指向的对象。然而,`...

    C++STL中智能指针介绍

    本文将详细介绍C++中的三种主要智能指针:`auto_ptr`、`unique_ptr`(C++11引入)和`shared_ptr`(C++11引入),以及它们的基本用法和注意事项。 1. `auto_ptr` `auto_ptr`是STL中最早提供的智能指针,它具有独占...

    c++11智能指针解析——揭开底层面纱,完整理解智能指针.pdf

    本篇文章将探讨C++11之前的`auto_ptr`以及C++11引入的`unique_ptr`、`shared_ptr`和`weak_ptr`。 首先,让我们看看`auto_ptr`。`auto_ptr`是C++98标准库中的一个智能指针,它使用模板定义,可以自动删除所指向的...

    05_请说一下你理解的 C++ 中的四个智能指针1

    C++标准库提供了四种类型的智能指针,分别是`auto_ptr`(已被弃用),`unique_ptr`,`shared_ptr`和`weak_ptr`。 1. `auto_ptr`: `auto_ptr`是C++98引入的,但在C++11中被弃用,因为它存在安全性问题。`auto_ptr`...

Global site tag (gtag.js) - Google Analytics