在这里,我们发现了一个垃圾收集机制真正能够发挥无可比拟的地方。借助于垃圾收集,前面讨论的RVL(返回值生命期)问题迎刃而解。由于垃圾收集的工作机制是释放那些不再被活跃代码所引用的内存,所以毫无疑问,当一个指向堆分配的内存块的指针在仍然被需要的时候是被会失效的。我们所要做的就是返回一个新分配的堆内存块而已。
template<typename T,
typename A = typename allocator_selector<T>::allocator_type,
typename P = do_construction<T>,
bool R = true>
class fixed_array_2d : protected A, public stl_collection_tag
{
public:
typedef fixed_array_2d< T, A, P, R > class_type;
typedef fixed_array_1d< T, A, P, false > dimension_element_type;
typedef A allocator_type;
typedef T value_type;
typedef value_type & reference;
typedef value_type const & const_reference;
typedef value_type * pointer;
typedef value_type const * const_pointer;
typedef size_t size_type;
typedef size_t index_type;
typedef ss_ptrdiff_t difference_type;
typedef bool bool_type;
typedef pointer_iterator< value_type, pointer, reference >::type iterator;
typedef pointer_iterator< value_type const , const_pointer, const_reference >::type const_iterator;
// 构造函数
private:
// 切片构造
fixed_array_2d(T *data, index_type d0, index_type d1);
public:
// 标准构造
fixed_array_2d (index_type d0, index_type d1);
fixed_array_2d (index_type d0, index_type d1, allocator_type const &ator);
fixed_array_2d (index_type d0, index_type d1, value_type const &t);
fixed_array_2d (index_type d0, index_type d1, value_type const &t, allocator_type const &ator);
fixed_array_2d (class_type const &rhs);
~fixed_array_2d();
allocator_type get_allocator () const;
void swap (class_type &rhs); throw ();
// 访问
public:
reference at (index_type i0, index_type i1);
const_reference at (index_type i0, index_type i1) const;
reference at_unchecked (index_type i0, index_type i1);
const_reference at_unchecked (index_type i0, index_type i1) const;
reference operator(); (index_type i0, index_type i1);
const_reference operator(); (index_type i0, index_type i1) const;
dimension_element_type at (index_type i0);
const dimension_element_type at (index_type i0) const;
dimension_element_type at_unchecked (index_type i0);
const dimension_element_type at_unchecked (index_type i0) const;
dimension_element_type operator[] (index_type i0);
const dimension_element_type operator[] (index_type i0) const;
reference front ();
reference back ();
const_reference front () const;
const_reference back () const;
pointer data ();
const_pointer data () const;
// 迭代
public:
iterator begin ();
iterator end ();
const_iterator begin () const;
const_iterator end () const;
// 状态
public:
index_type dimension0 () const;
index_type dimension1 () const;
index_type size () const;
bool_type empty () const;
static size_type max_size ();
// 实现
private:
pointer allocate_(size_type n);
void deallocate_(pointer p, size_type n);
pointer data_();
index_type calc_index_(index_type i0, index_type i1) const;
void range_check_(index_type i0, index_type i1) const;
void range_check_(index_type i0) const;
allocator_type& get_allocator_();
// 成员
private:
T* m_data;
index_type m_d0;
index_type m_d1;
size_type m_size;
friend class fixed_array_3d<T, A, P, true>;
friend class fixed_array_3d<T, A, P, false>;
// 声明但不实现
private:
class_type const& operator =(class_type const& rhs);
};
另外,C/C++对固定大小的数组支持是无容置疑的,但为了获得通过bein()/end()来获得对整个数组进行迭代的能力,我们也设计了一组模板类来模拟静态多维数组。static_array自身并不进行任何形式的内存分配:如果它的身份是作为一个切片代理,它只会保存一个指向数组切片的指针;倘若它本身作为一个完整的数组,则会包含一个完整的N维内建数组。
泛化的仿函数 —— 类型隧道(Type Tunneling):是一种通过访问垫片使两个逻辑相关但物理不相关的类型能够互操作的机制,垫片允许一个外部类型通过一个接口以一种可识别且兼容的形式呈现于内部类型的面前。
template<typename C,
typename A = C const *>
class is_large : public std::unary_function<A, bool>
{
public:
template<typename S>
bool operator ()(S const& file) const
{
return is_large_(c_str_ptr(file)); // c_str_ptr垫片
}
private:
static bool is_large_(C const* file)
{
...
}
};
glob_sequence gs("/usr/include/", "impcpp*");
std::count_if(gs.begin(), gs.end(), is_large<char>());
glob_sequenc_w gsw(L"/usr/include/", L"impcpp*");
std::count_if(gsw.begin(), gsw.end(), is_large<wchar_t>());
readir_sequence rs("/usr/include/");
std::count_if(rs.begin(), rs.end(), is_large<char>());