正确使用std::auto_ptr

转自:http://blog.csdn.net/just_a_beginning/article/details/4386755

这里面的实例,很好。可以参考auto_ptr源码

	// TEMPLATE CLASS auto_ptr
template<class _Ty>
	class auto_ptr;

template<class _Ty>
	struct auto_ptr_ref
		{	// proxy reference for auto_ptr copying
	explicit auto_ptr_ref(_Ty *_Right)
		: _Ref(_Right)
		{	// construct from generic pointer to auto_ptr ptr
		}

	_Ty *_Ref;	// generic pointer to auto_ptr ptr
	};

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

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

	auto_ptr(auto_ptr<_Ty>& _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>
		auto_ptr<_Ty>& 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
		}

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

	auto_ptr<_Ty>& 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
		if (_Myptr != 0)
			delete _Myptr;
		}

	_Ty& operator*() const _THROW0()
		{	// return designated value

 #if _HAS_ITERATOR_DEBUGGING
		if (_Myptr == 0)
			_DEBUG_ERROR("auto_ptr not dereferencable");
 #endif /* _HAS_ITERATOR_DEBUGGING */

		__analysis_assume(_Myptr);

		return (*get());
		}

	_Ty *operator->() const _THROW0()
		{	// return pointer to class object

 #if _HAS_ITERATOR_DEBUGGING
		if (_Myptr == 0)
			_DEBUG_ERROR("auto_ptr not dereferencable");
 #endif /* _HAS_ITERATOR_DEBUGGING */

		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 && _Myptr != 0)
			delete _Myptr;
		_Myptr = _Ptr;
		}

private:
	_Ty *_Myptr;	// the wrapped object pointer
	};


 

1, auto_ptr类

auto_ptr是一个模板类,定义如下:

template <typenameType>
class
auto_ptr {...};

它存储的是一个指向Type的指针。

顾名思义,auto_ptr是一种智能指针,它包含一个动态分配内存的指针,并在它生命周期结束的时候,销毁包含的指针所指向的内存。

 


 

例1:

 

 

     void f()

    {

        Type* pt(new Type);

        //一些代码...

        delete pt;
    }

 

这样的代码很常见,但它有可能造成内存泄露。首先你用了new,你就要记得用delete,但即使你记住了用delete,还是会出问题。如果f()在执行delete pt之前,就抛出了异常,函数返回了。那么这个分配的对象就没被删除。

 


 

使用auto_ptr,很优雅的解决了这些问题。

例2:

         void f()

        {

              auto_ptr<Type> pt(new Type);

              //一些代码...
        }

现在的代码,不会泄露Type类型的对象。不管是函数正常结束,还是抛出异常结束,都会调用pt的析构函数,从而删除分配的对象。

 

 

 

 

2, auto_ptr构造函数

构造函数1:explicitauto_ptr(Type*_Ptr = 0) throw( );

 

            auto_ptr<int> pt;                          //包含一个int*的指针,并初始化为NULL

            auto_ptr<int> pt(new int(123));//包含一个int*的指针,并初始化为123的地址

            auto_ptr<int> pt =new int(123); //error!构造函数声明为explicit

 


 

构造函数2:auto_ptr(auto_ptr<Type>&_Right) throw( );

 

            int* ptr =new int();

            auto_ptr<int> pt1(ptr); //构造函数1

            auto_ptr<int> pt2(pt1);//将pt1的使用权转给pt2,注意pt1指向NULL了

                                    //pt1调用了本身的release()函数,将内部指针地址传给pt2

 

 

构造函数3:template<typename Other>       

               auto_ptr(auto_ptr<Other>&_Right) throw( );

                          声明这样一个拷贝构造函数的目的,就是为了派生类指针能转换成基类的指针。

 

例:

      class Base { };

      class Derived :public Base { };

 

      auto_ptr<Derived> pDerived(new Derived);

      auto_ptr<Base>    pBase(pDerived);          //让这样的代码能通过编译器

 

           其本质是为了让,auto_ptr类内部的Derived*转换为Base*

 


 

构造函数4:auto_ptr(auto_ptr_ref<Type>_Right) throw( );

                        //暂略

 

 

 

3, auto_ptr成员函数

 

成员函数1:Type* get( )const throw( );

                    获得包含指针的地址

 

                   int* ptr = new int(123);

                   auto_ptr<int> pt(ptr);

                   assert(pt.get() == ptr); //相等,指向同一地址

 

成员函数2:Type* release( )throw( );

                   返回包含指针的地址,并将包含指针设为NUll

                   string* pstr = new string("hello");

                   auto_ptr<string> pt(pstr);

                   pt.release();   //不在指向string对象

                                       //此时,pt.get()等于NULL

                   delete pstr;    //应该手动删除pstr指向的内存块 

                  

成员函数3:void reset(Type* _Ptr = 0);

                   double* pdouble1 = new double(3.14);

                   double* pdouble2 = new double(1.23);

                   auto_ptr<double> pt1(pdouble1);

                   pt1.reset(pdouble2);  //将删除pt1所指向的内存块就是pdouble1指向的那块

                                                 //此时,pt.get()等于pdouble2

                   cout << *pdouble1;   //error,pdouble已经是野指针了。

                  

                  

                   

              

4, 使用总结

1,auto_ptr存储的指针应该为NULL或者指向动态分配的内存块。

2,auto_ptr存储的指针应该指向单一物件(是new出来的,而不是new[]出来的)。

3,两个auto_ptr对象不会同时指向同一块内存块。要明白2个auto_ptr对象赋值会发生什么。

4,千万不要把auto_ptr对象放在容器中。

5,当将auto_ptr作为函数参数时,最好声明为const auto_ptr<T>&(by const ref).当函数返回值可以简单的传值(by value).

 

使用C++中的智能指针时,可以使用`std::shared_ptr`和`std::make_shared`来管理动态分配的内存。 下面是一个使用`std::shared_ptr`和`std::make_shared`的示例: ```cpp #include <memory> #include <iostream> class MyClass { public: MyClass() { std::cout << "MyClass constructor called" << std::endl; } ~MyClass() { std::cout << "MyClass destructor called" << std::endl; } }; int main() { // 使用std::shared_ptr进行动态内存分配 std::shared_ptr<MyClass> ptr1(new MyClass); std::cout << "The use count of ptr1 is: " << ptr1.use_count() << std::endl; { // 使用std::make_shared进行动态内存分配 auto ptr2 = std::make_shared<MyClass>(); std::cout << "The use count of ptr2 is: " << ptr2.use_count() << std::endl; // 将ptr2赋值给ptr3,引用计数会自动增加 std::shared_ptr<MyClass> ptr3 = ptr2; std::cout << "The use count of ptr3 is: " << ptr3.use_count() << std::endl; } // 这里ptr2和ptr3超出作用域,引用计数减少 std::cout << "The use count of ptr1 is: " << ptr1.use_count() << std::endl; return 0; } ``` 上述示例中,我们首先使用`std::shared_ptr`手动分配一个`MyClass`对象,并使用`new`关键字进行初始化。然后,我们使用`std::make_shared`来动态分配另一个`MyClass`对象,并自动进行对象的构造和内存管理。 在示例的后续部分,我们展示了智能指针的引用计数特性。当我们将一个`std::shared_ptr`赋值给另一个时,引用计数会增加。当超出作用域后,引用计数会减少。这样可以确保在没有任何对象使用该内存时,内存得到正确释放。 请注意,使用智能指针可以避免显式地调用`delete`来释放内存,从而减少了内存泄漏和悬空指针的风险。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值