在本章,我們通過(guò)考察5個(gè)不完美的將整形轉(zhuǎn)換為字符串類(lèi)型的技術(shù),探討下C++中返回值生命期的各種問(wèn)題和陷阱,最后總結(jié)垃圾收集機(jī)制的一個(gè)實(shí)際價(jià)值。
在這里,我們發(fā)現(xiàn)了一個(gè)垃圾收集機(jī)制真正能夠發(fā)揮無(wú)可比擬的地方。借助于垃圾收集,前面討論的RVL(返回值生命期)問(wèn)題迎刃而解。由于垃圾收集的工作機(jī)制是釋放那些不再被活躍代碼所引用的內(nèi)存,所以毫無(wú)疑問(wèn),當(dāng)一個(gè)指向堆分配的內(nèi)存塊的指針在仍然被需要的時(shí)候是被會(huì)失效的。我們所要做的就是返回一個(gè)新分配的堆內(nèi)存塊而已。
C/C++不支持各維大小都是動(dòng)態(tài)的多維數(shù)組,但我們可以借助語(yǔ)言?xún)?nèi)建對(duì)多維數(shù)組進(jìn)行“切片”的能力實(shí)現(xiàn)一個(gè)自定義的多維數(shù)組類(lèi)(容器)。
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;
// 構(gòu)造函數(shù)
private:
// 切片構(gòu)造
fixed_array_2d(T *data, index_type d0, index_type d1);
public:
// 標(biāo)準(zhǔn)構(gòu)造
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 ();
// 訪問(wèn)
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;
// 狀態(tài)
public:
index_type dimension0 () const;
index_type dimension1 () const;
index_type size () const;
bool_type empty () const;
static size_type max_size ();
// 實(shí)現(xiàn)
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>;
// 聲明但不實(shí)現(xiàn)
private:
class_type const& operator =(class_type const& rhs);
};
另外,C/C++對(duì)固定大小的數(shù)組支持是無(wú)容置疑的,但為了獲得通過(guò)bein()/end()來(lái)獲得對(duì)整個(gè)數(shù)組進(jìn)行迭代的能力,我們也設(shè)計(jì)了一組模板類(lèi)來(lái)模擬靜態(tài)多維數(shù)組。static_array自身并不進(jìn)行任何形式的內(nèi)存分配:如果它的身份是作為一個(gè)切片代理,它只會(huì)保存一個(gè)指向數(shù)組切片的指針;倘若它本身作為一個(gè)完整的數(shù)組,則會(huì)包含一個(gè)完整的N維內(nèi)建數(shù)組。
泛化的仿函數(shù) —— 類(lèi)型隧道(Type Tunneling):是一種通過(guò)訪問(wèn)墊片使兩個(gè)邏輯相關(guān)但物理不相關(guān)的類(lèi)型能夠互操作的機(jī)制,墊片允許一個(gè)外部類(lèi)型通過(guò)一個(gè)接口以一種可識(shí)別且兼容的形式呈現(xiàn)于內(nèi)部類(lèi)型的面前。
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>());
雖然某些老版本的編譯器不支持局部仿函數(shù)類(lèi)用于STL算法(VS2008支持的還不錯(cuò)),但當(dāng)我們遇到回調(diào)枚舉API時(shí),局部類(lèi)是個(gè)非常不錯(cuò)的選擇。