您的位置:首页 > 运维架构

scoped_array源码剖析

2017-01-20 19:38 507 查看
scoped_array很想scoped_ptr,它包装了new[]操作符(不是单纯的new)在堆上分配的动态数组,为动态数组提供了一个代理,保证可以正确的释放内存。



源码剖析

scoped_array的源码如下:

namespace boost
{

//  scoped_array extends scoped_ptr to arrays. Deletion of the array pointed to
//  is guaranteed, either on destruction of the scoped_array or via an explicit
//  reset(). Use shared_array or std::vector if your needs are more complex.

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) // never throws (but has a BOOST_ASSERT in it, so not marked with BOOST_NOEXCEPT)
{
BOOST_ASSERT( p == 0 || p != px ); // catch self-reset errors
this_type(p).swap(*this);
}

//重载了operator[]模拟数组,但不支持*(p+i)这种访问方式
T & operator[](std::ptrdiff_t i) const // never throws (but has a BOOST_ASSERT in it, so not marked with BOOST_NOEXCEPT)
{
BOOST_ASSERT( px != 0 );
BOOST_ASSERT( i >= 0 );
return px[i];
}

T * get() const BOOST_NOEXCEPT
{
return px;
}

// implicit conversion to "bool"
#include <boost/smart_ptr/detail/operator_bool.hpp>

void swap(scoped_array & b) BOOST_NOEXCEPT
{
T * tmp = b.px;
b.px = px;
px = tmp;
}
};

template<class T> inline void swap(scoped_array<T> & a, scoped_array<T> & b) BOOST_NOEXCEPT
{
a.swap(b);
}

} // namespace boost


上面的源码和我之前分析过的scoped_ptr类似,只不过变成了对数组的封装。scoped_array析构函数中的check_delete实现是这样的:

template<class T> inline void checked_array_delete(T * x)
{
typedef char type_must_be_complete[ sizeof(T)? 1: -1 ];
(void) sizeof(type_must_be_complete);
delete [] x;
}


呵呵,这里是delete[] x。



特点

scoped_array的主要特点如下:

构造函数接受的指针p必须是new[]的结果,而不能是new表达式的结果。

没有*、->操作符重载,因为scoped_array持有的不是一个普通指针。

析构函数使用delete []释放资源,而不是delete。

提供operator[]操作符重载,可以像普通数组一样用下标访问元素。

没有begin()、end()等类似容器的迭代器操作函数



用法

sceopd_array与scoped_ptr源于相同的设计思想,故而用法非常相似:它只能在被生命的作用域内使用,不能拷贝、赋值。唯一不同的是scoped_array包装的是new[]产生的指针,并在析构时调用delete[],因为它管理的是动态数组,而不是单个对象

代码示例:

class test {
public:
test() { cout<<"ctor"<<endl; }
~test() { cout<<"dtor"<<endl; }
};

int main()
{
int *arr = new int[100];
scoped_array<int> sa(arr);

std::fill_n(&sa[0], 100, 5);
sa[10] = sa[20] + sa[30];

cout<<sa[10]<<endl;

scoped_array<test> ptest(new test[3]);

return 0;
}


scoped_array重载了operator[],因此用起来就像是一个普通的数组,但不能使用”首地址+N”的方式访问元素,并且scoped_array不提供数组索引的范围检查,如果使用超过动态数组大小的索引或者是负数索引将引发未定义行为。



使用建议

scoped_array没有给程序增加额外的负担,它的速度与原始数组同样快。但scoped_array功能很有限,不能动态增长。也没有迭代器支持,不能搭配STL算法,仅有一个纯粹的”裸”数组接口。而且我们要尽量避免使用new[]操作符,尽量使用scoped_array,甚至是更好的std::vector。



参考:

Boost程序库完全开发指南,作者:罗剑锋
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息