scoped_array原始碼剖析
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程式庫完全開發指南,作者:羅劍鋒
相關文章
- Java集合原始碼剖析——ArrayList原始碼剖析Java原始碼
- 【Java集合原始碼剖析】ArrayList原始碼剖析Java原始碼
- 【Java集合原始碼剖析】Vector原始碼剖析Java原始碼
- 【Java集合原始碼剖析】HashMap原始碼剖析Java原始碼HashMap
- 【Java集合原始碼剖析】Hashtable原始碼剖析Java原始碼
- 【Java集合原始碼剖析】TreeMap原始碼剖析Java原始碼
- 【Java集合原始碼剖析】LinkedList原始碼剖析Java原始碼
- 【Java集合原始碼剖析】LinkedHashmap原始碼剖析Java原始碼HashMap
- epoll–原始碼剖析原始碼
- HashMap原始碼剖析HashMap原始碼
- Alamofire 原始碼剖析原始碼
- Handler原始碼剖析原始碼
- Kafka 原始碼剖析Kafka原始碼
- TreeMap原始碼剖析原始碼
- SDWebImage原始碼剖析(-)Web原始碼
- Boost原始碼剖析--原始碼
- Spring原始碼剖析9:Spring事務原始碼剖析Spring原始碼
- Flutter 原始碼剖析(一)Flutter原始碼
- 全面剖析 Redux 原始碼Redux原始碼
- vue原始碼剖析(一)Vue原始碼
- Kafka 原始碼剖析(一)Kafka原始碼
- Thread原始碼剖析thread原始碼
- Retrofit 原始碼剖析-深入原始碼
- SDWebImage原始碼剖析(二)Web原始碼
- iOS Aspects原始碼剖析iOS原始碼
- Apache Spark原始碼剖析ApacheSpark原始碼
- 《STL原始碼剖析》-- memory原始碼
- mmdetection原始碼剖析(1)--NMS原始碼
- Java LinkedList 原始碼剖析Java原始碼
- 深入剖析RocketMQ原始碼-NameServerMQ原始碼Server
- spark核心原始碼深度剖析Spark原始碼
- STL原始碼剖析——vector容器原始碼
- 深入剖析(JDK)ArrayQueue原始碼JDK原始碼
- 深入剖析LinkedList原始碼原始碼
- ThreadLocal原始碼深度剖析thread原始碼
- scoped_ptr原始碼剖析原始碼
- EMPI原始碼剖析(原創)原始碼
- Java集合:HashMap原始碼剖析JavaHashMap原始碼