我是靠谱客的博主 踏实画板,最近开发中收集的这篇文章主要介绍智能指针源码分析(1)——scoped_ptr&scoped_array,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

文章目录

        • 一、scoped_ptr
            • 1.简介
            • 2.简单的源码
            • 3.实现一个自己的scoped_ptr智能指针
        • 二、scoped_array
            • 1.源码
            • 2.自己动手写scoped_array

一、scoped_ptr

1.简介

scoped_ptr是一个类似于auto_ptr的智能指针,它包装了new操作符在堆上分配的动态对象,能够保证动态创建的对象在任何时候都可以被正确的删除。但是scoped_ptr的所有权更加严格,不能转让,即不支持拷贝构造函数与重载赋值运算符,一旦scoped_pstr获取了对象的管理权,你就无法再从它那里取回来。当然调用reset函数对scoped_ptr重新赋值还是可以的,它会自动释放前面管理的对象。看如下实例:(编译前需要yum install boost-devel安装boost库)

#include <iostream>
#include <string>
#include <memory>
#include <boost/scoped_ptr.hpp>
using namespace std;
class book{
	public:
		book(){
			cout<<"create the "<<sort<<" book"<<endl;
			sort++;
		}
		~book(){
			cout<<"~ "<<sort<<"book"<<endl;sort++;
		}
	private:
		static int sort;
};
int book::sort=0;
int main(){
	int *p = new int(10);
	boost::scoped_ptr<int> ps(p);   
	cout<<*ps<<endl;                
	book *px = new book;
	boost::scoped_ptr<book>ps1(px);
	ps1.reset(new book);
	auto_ptr<book>au(new book);
	boost::scoped_ptr<book>ps2(au);
	return 0;
}

输出如下:

10
create the 0 book
create the 1 book
~ 2book
create the 3 book
~ 4book
~ 5book
2.简单的源码

观其使用方式和auto_ptr等常用智能指针几乎差不多,现在颇为让人费解的就是为什么不支持拷贝与赋值以及reset是怎样实现的是像我们想的那样直接删除再赋值还是怎么的?别急,来看源码:

//boost_1_55_0boostsmart_ptrscoped_ptr.hpp
 template<class T> class scoped_ptr // noncopyable
{
private:

    T * px;
    scoped_ptr(scoped_ptr const &);
    scoped_ptr & operator=(scoped_ptr const &);
    typedef scoped_ptr<T> this_type;
    void operator==( scoped_ptr const& ) const;
    void operator!=( scoped_ptr const& ) const;
public:
    typedef T element_type;

    explicit scoped_ptr( T * p = 0 ): px( p ) // never throws
    {    }
    explicit scoped_ptr( std::auto_ptr<T> p ) BOOST_NOEXCEPT : px( p.release() )
    {    }

    ~scoped_ptr() // never throws
    {
        boost::checked_delete( px );    //该函数先检查模板参数T的完整性,然后释放px对象
    }

    void reset(T * p = 0) // never throws
    {
        BOOST_ASSERT( p == 0 || p != px ); // catch self-reset errors
        this_type(p).swap(*this);
    }

    T & operator*() const // never throws
    {
        BOOST_ASSERT( px != 0 );
        return *px;
    }

    T * operator->() const // never throws
    {
        BOOST_ASSERT( px != 0 );
        return px;
    }

    T * get() const BOOST_NOEXCEPT
    {
        return px;
    }
    void swap(scoped_ptr & b) BOOST_NOEXCEPT	//#define BOOST_NOEXCEPT noexcept
    {
        T * tmp = b.px;
        b.px = px;
        px = tmp;
    }
};
  • 定义了可接受auto_ptr为参数的智能指针,也只有auto_ptr才满足这个特性
  • reset函数:借助临时构造scoped_ptr对象调用swap函数交换函数参数与自身的管理对象px,这样临时对象在swap函数结束之后会自动调用析构函数释放前面管理对象的空间以免造成内存泄漏。
  • 重载了*(取值)运算符返回对象的引用;重载了->(成员选择)运算符返回对象的指针。
  • 定义了get函数返回裸指针千万注意不要delete其返回的指针,最后swap函数交换同类智能指针内部的数据指针。
  • 掌握noexcept为C++11的关键字,表示函数中不会发生异常,这有利于编译器对程序做更多的优化。如果在运行时,noexecpt函数向外抛出了异常(如果函数内部捕捉了异常并完成处理,这种情况不算抛出异常),程序会直接终止。
  • 掌握析构函数中的checked_delete函数,该函数delete前面两句是为了校验类型T的完整性:
/*boost_1_55_0boostchecked_delete.hpp*/
template<class T> inline void checked_delete(T * x)
{
    // intentionally complex - simplification causes regressions
    typedef char type_must_be_complete[ sizeof(T)? 1: -1 ];
    (void) sizeof(type_must_be_complete);
    delete x;
}
  • 缺点由源码可以知道scoped_ptr只支持对单个动态分配元素的处理,不能对数组进行处理
3.实现一个自己的scoped_ptr智能指针
#include <iostream>
#include <memory>
#include <string>
using namespace std;
template<class T> class scoped_ptr 
{
private:
    T * px;
    scoped_ptr(scoped_ptr const &);
    scoped_ptr & operator=(scoped_ptr const &);
    typedef scoped_ptr<T> this_type;
    void operator==( scoped_ptr const& ) const;
    void operator!=( scoped_ptr const& ) const;
public:
    typedef T element_type;

    explicit scoped_ptr( T * p = 0 ): px( p ){}
    explicit scoped_ptr( std::auto_ptr<T> p )  : px( p.release() ){}
    ~scoped_ptr() 
    {
        delete px;	//默认使用类型完整
    }
    void reset(T * p = 0) // never throws
    {
        if( p == 0 || p != px )// catch self-reset errors
        	this_type(p).swap(*this);
    }

    T & operator*() const // never throws
    {
        if( px != 0 )
        	return *px;
    }

    T * operator->() const // never throws
    {
        if( px != 0 )
        	return px;
    }

    T * get() const
    {
        return px;
    }
    void swap(scoped_ptr & b)
    {
        T * tmp = b.px;
        b.px = px;
        px = tmp;
    }
};
int main(){
	int *p = new int(10);
	scoped_ptr<int> ps(p);
	cout<<*ps<<endl;
	string *px = new string("Hello world!");
	scoped_ptr<string>ps1(px);
	cout<<ps1->c_str()<<endl;
	return 0;
}

二、scoped_array

1.源码

其实就是比scoped_ptr相比是直接用于处理数组而已,直接看源码:

template<class T> class scoped_array // noncopyable
{
private:
    T * px;
    scoped_array(scoped_array const &);
    scoped_array & operator=(scoped_array const &);
    typedef scoped_array<T> this_type;
    void operator==( scoped_array const& ) const;
    void operator!=( scoped_array const& ) const;
public:
    typedef T element_type;
    explicit scoped_array( T * p = 0 ) BOOST_NOEXCEPT : px( p ){}
    ~scoped_array() // never throws
    {
        boost::checked_array_delete( px );
    }

    void reset(T * p = 0) 
    {
        BOOST_ASSERT( p == 0 || p != px ); // catch self-reset errors
        this_type(p).swap(*this);
    }

    T & operator[](std::ptrdiff_t i) const
    {
        BOOST_ASSERT( px != 0 );
        BOOST_ASSERT( i >= 0 );
        return px[i];
    }

    T * get() const BOOST_NOEXCEPT
    {
        return px;
    }
  void swap(scoped_array & b) BOOST_NOEXCEPT
    {
        T * tmp = b.px;
        b.px = px;
        px = tmp;
    }
};
  • 定义了reset操作,同ptr的
  • 重载了[]运算符,可以像普通指针那样使用
  • 支持get与swap操作
  • 缺点:不能支持动态增长,没有迭代器的支持,不能搭配STL算法,不推荐使用
2.自己动手写scoped_array
#include <iostream>
#include <memory>
#include <string>
using namespace std;
template<class T> class scoped_array
{
private:
    T * px;
    scoped_array(scoped_array const &);
    scoped_array & operator=(scoped_array const &);
    typedef scoped_array<T> this_type;
    void operator==( scoped_array const& ) const;
    void operator!=( scoped_array const& ) const;
public:
    explicit scoped_array( T * p = 0 ): px( p ){}

    ~scoped_array() 
    {
        delete px;	
    }
    void reset(T * p = 0) // never throws
    {
        if( p == 0 || p != px )// catch self-reset errors
        	this_type(p).swap(*this);
    }
	T & operator[](int i) const // never throws
    {
        if( px != 0 && i>=0)
        	return px[i];
    }
    T * operator+(int i) const // never throws
    {
        if( px != 0 )
        	return (px+i);
    }
    T & operator*() const // never throws
    {
        if( px != 0 )
        	return *px;
    }

    T * get() const
    {
        return px;
    }
    void swap(scoped_array & b)
    {
        T * tmp = b.px;
        b.px = px;
        px = tmp;
    }
};
int main(){
	int *p = new int[10];
	scoped_array<int> ps(p);
	for(int i=0;i<10;i++)
		ps[i] = i;
	for(int i=0;i<10;i++){
		cout<<*(ps+i)<<' '<<ps[i]<<endl;
	}
	int *ssr = new int[10];
	for(int i=0;i<10;i++)
		ssr[i] = i+100;
	ps.reset(ssr);
	for(int i=0;i<10;i++)
		cout<<*(ps+i)<<' '<<ps[i]<<endl;
	return 0;
}

输出如下:

0 0
1 1
2 2
3 3
4 4
5 5
6 6
7 7
8 8
9 9
100 100
101 101
102 102
103 103
104 104
105 105
106 106
107 107
108 108
109 109

最后

以上就是踏实画板为你收集整理的智能指针源码分析(1)——scoped_ptr&scoped_array的全部内容,希望文章能够帮你解决智能指针源码分析(1)——scoped_ptr&scoped_array所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(34)

评论列表共有 0 条评论

立即
投稿
返回
顶部