青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

posts - 13, comments - 4, trackbacks - 0, articles - 0
  C++博客 :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

Imperfect C++ 讀書筆記(六)

Posted on 2008-11-26 20:44 Batiliu 閱讀(483) 評(píng)論(0)  編輯 收藏 引用 所屬分類: 讀書筆記

返回值生命期

在本章,我們通過(guò)考察5個(gè)不完美的將整形轉(zhuǎn)換為字符串類型的技術(shù),探討下C++中返回值生命期的各種問題和陷阱,最后總結(jié)垃圾收集機(jī)制的一個(gè)實(shí)際價(jià)值。

  1. integer_to_string<>
    template<typename C>
    C const* integer_to_string(C* buf, size_t cchBuf, sint8_t i)
    {
        return signed_integer_to_string(buf, cchBuf, i);
    }
    ...
    template<typename C>
    C const* integer_to_string(C* buf, size_t cchBuf, uint8_t i)
    {
        return unsigned_integer_to_string(buf, cchBuf, i);
    }
     
    template<typename C, typename I>
    inline const C *signed_integer_to_string(C* buf, size_t cchBuf, I i)
    {
        C* psz = const_cast<C*>(unsigned_integer_to_string(buf, cchBuf, i));
        if (i < 0)
        {
            --psz;
            *psz = C('-');
        }
        return psz;
    }
     
    template<typename C, typename I>
    inline const C* unsigned_integer_to_string(C* buf, size_t cchBuf, I i)
    {
        C* psz = buf + cchBuf - 1;
        *psz = 0;
        do
        {
            unsigned lsd = i % 10;
            i /= 10;
            --psz;
            *psz = get_digit_character<C>()[lsd];
        } while (i != 0);
        return psz;
    }
    template<typename C>
    const C* get_digit_character()
    {
        static const C s_characters[19] =
        {
            '9', '8', '7', '6', '5', '4', '3', '2', '1',
            '0',
            '1', '2', '3', '4', '5', '6', '7', '8', '9'
        };
        static const C* s_mid = s_characters + 9;
        return s_mid;
    }

    該方案效率很高,僅相當(dāng)于spintf()開銷的10%。然而,也并非完美無(wú)缺。首先,它不算十分簡(jiǎn)潔:需要用戶提供緩沖區(qū)的指針和緩沖區(qū)的長(zhǎng)度。其次,更重要的一點(diǎn),用戶提供的緩沖區(qū)長(zhǎng)度有可能是錯(cuò)誤的。如果太小,也許還能在調(diào)試版中引發(fā)一個(gè)斷言,如果大于緩沖區(qū)真實(shí)的長(zhǎng)度,就有可能發(fā)生緩沖區(qū)溢出。

  2. TSS

    利用TSS(Thread-Specific Storage,線程相關(guān)存儲(chǔ)),我們可以提供一個(gè)線程安全的內(nèi)部緩沖區(qū),就只需提供待轉(zhuǎn)換的整型值一個(gè)參數(shù)即可了。

    template<typename C, typename I>
    C const* int_to_string(I i)
    {
        const size_t CCH = 21;    // 足以容納64位有符號(hào)整型的最大值
        C *  buf = get_tss_buffer<C, CCH>();
        return integer_to_string(buf, CCH, i);
    }
     
    template<typename C, size_t CCH>
    C* get_tss_buffer()
    {
        __declspec(thread) static C s_buffer[CCH];
        return s_buffer;
    }

    注:__declspec(thread)是微軟Win32編譯器提供的擴(kuò)展,如果需要跨平臺(tái)或跨編譯器,可以考慮選擇其他合適的TLS庫(kù)。
    該方案有個(gè)小小的不便就是,無(wú)法推導(dǎo)字符類型了,需要顯式地參數(shù)化函數(shù)模板。如:int_to_string<char>(10)。
    然而,還有個(gè)更顯著的缺陷,就是無(wú)法再單個(gè)表達(dá)式中被多次調(diào)用。如:printf("%s, %s", int_to_string<char>(5), int_to_string<char>(10));

  3. 擴(kuò)展RVL

    為了解決方案2的在同一表達(dá)式中不能連續(xù)調(diào)用的問題,可以運(yùn)用一個(gè)技巧讓其沖突的可能性降低。

    template<typename C, size_t CCH>
    C* get_tss_buffer()
    {
        const size_t DEGREE = 32;
        __declspec(thread) static C s_buffer[DEGREE][CCH];
        __declspec(thread) static size_t s_index;
        s_index = (s_index + 1) % DEGREE;
        return s_buffer[s_index];
    }

    這里的32只是一個(gè)猜測(cè)值,即假定單個(gè)表達(dá)式中最多不超過(guò)32個(gè)同一類整型到字符串的轉(zhuǎn)換。32表示“安全”和棧大小之間的一個(gè)折衷,相對(duì)于方案2給用戶提供了一種虛假的安全感,所以并不推薦使用。

  4. 靜態(tài)數(shù)組大小決議

    針對(duì)方案1,我們利用編譯器能夠推導(dǎo)出數(shù)組的靜態(tài)大小。我們可以定義integer_to_string()函數(shù)的一個(gè)新的重載版本,它接受一個(gè)數(shù)組為參數(shù),而不是自帶緩沖區(qū)長(zhǎng)度的指針。

    template<typename C, size_t N>
    C const* integer_to_string(C(&buf)[N], sint8_t i)
    {
        STATIC_ASSERT(!(N < printf_traits<sint8_t>::size));
        return integer_to_string(buf, cchBuf, i);
    }

    該方案消除了錯(cuò)誤的緩沖區(qū)長(zhǎng)度被傳遞給函數(shù)的可能性,更妙的是,我們可以使用靜態(tài)斷言來(lái)進(jìn)行編譯器檢查,從而確保緩沖區(qū)長(zhǎng)度是足夠的。該方案是線程安全的,且不需要進(jìn)行任何顯式實(shí)例化,如:

    uint64_t i = ...
    char buff[12];
    char const* s = integer_to_string(buff, i);

    這個(gè)方案唯一的缺點(diǎn)就是我們?nèi)匀贿€得提供一個(gè)緩沖區(qū)。

  5. 轉(zhuǎn)換墊片
    最后一個(gè)解決方案,不再像前面的解決方案一樣返回一個(gè)指針,它走了另一條不同的路:使用一個(gè)代理類,返回該代理類的實(shí)例。當(dāng)然,幕后仍然是integer_to_string()函數(shù)在承擔(dān)著實(shí)際的轉(zhuǎn)換工作。
    template<typename C, typename I>
    class int_to_string_proxy
    {
    public:
        typedef C char_type;
        typedef I int_type;
    public:
        int_to_string_proxy(int_type i)
            : m_result(integer_to_string(m_sz, dimensionof(m_sz), i))
        {}
        int_to_string_proxy(int_to_string_proxy const& rhs)
            : m_result(m_sz)
        {
            char_type* dest = m_sz;
            char_type const* src = rhs.m_result;
            while (0 != (*dest++ = *src++))
            {}
        }
        operator char_type const* () const
        {
            return m_result;
        }
    private:
        char_type const * const m_result;
        char_type m_sz[21];
    private:
        int_to_string_proxy& operator =(int_to_string_proxy& rhs);
    };
     
    template<typename C, typename I>
    int_to_string_proxy<C, I> int_to_string(I i)
    {
        return int_to_string_proxy<C, I>(i);
    }

與所有轉(zhuǎn)換墊片一樣,該方案受到RVL-PDP(析構(gòu)后指針)問題的困擾。它需要在表達(dá)式中立即使用返回值,而不應(yīng)該保留到以后使用。

在這里,我們發(fā)現(xiàn)了一個(gè)垃圾收集機(jī)制真正能夠發(fā)揮無(wú)可比擬的地方。借助于垃圾收集,前面討論的RVL(返回值生命期)問題迎刃而解。由于垃圾收集的工作機(jī)制是釋放那些不再被活躍代碼所引用的內(nèi)存,所以毫無(wú)疑問,當(dāng)一個(gè)指向堆分配的內(nèi)存塊的指針在仍然被需要的時(shí)候是被會(huì)失效的。我們所要做的就是返回一個(gè)新分配的堆內(nèi)存塊而已。

 

多維數(shù)組

C/C++不支持各維大小都是動(dòng)態(tài)的多維數(shù)組,但我們可以借助語(yǔ)言內(nèi)建對(duì)多維數(shù)組進(jìn)行“切片”的能力實(shí)現(xiàn)一個(gè)自定義的多維數(shù)組類(容器)。

作者給出的fixed_array系列多維數(shù)組類模板具有以下幾個(gè)顯著的特征:

  1. 每一個(gè)模板都維護(hù)一個(gè)指向一維內(nèi)存快的指針,其他存放的是邏輯上N維的數(shù)組元素。
  2. 每一個(gè)類都有一個(gè)dimension_element_type成員類型,該成員的類型對(duì)一維數(shù)組類其實(shí)就是value_type,對(duì)高維數(shù)組類就是比它低一維的數(shù)組模板。
  3. begin()和end()方法返回的迭代器表示整個(gè)多維數(shù)組所有的元素集合區(qū)間,這便意味著,可以是使用同一stl算法(如 std::for_each())來(lái)處理不同維數(shù)的數(shù)組。
  4. 一個(gè)數(shù)組模板不但自身能夠作為一個(gè)完整的多維數(shù)組類,而且還能夠作為比它更高維的數(shù)組模板的子數(shù)組切片。作為完整多維數(shù)組類時(shí),其模板參數(shù)R為true,其標(biāo)準(zhǔn)構(gòu)造函數(shù)會(huì)分配相應(yīng)的內(nèi)存。作為其他更高維度數(shù)組的子數(shù)組切片時(shí),其模板參數(shù)R為false,其切片構(gòu)造函數(shù)只是接受一個(gè)相應(yīng)的子數(shù)組切片指針。
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 ();
 
// 訪問
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)模擬靜態(tài)多維數(shù)組。static_array自身并不進(jìn)行任何形式的內(nèi)存分配:如果它的身份是作為一個(gè)切片代理,它只會(huì)保存一個(gè)指向數(shù)組切片的指針;倘若它本身作為一個(gè)完整的數(shù)組,則會(huì)包含一個(gè)完整的N維內(nèi)建數(shù)組。

template<typename T,
    size_t N0,
    size_t N1,
    typename P = do_construction<T>,
    typename M = T[N0 * N1]>
class static_array_2d : public null_allocator<T>, public stl_collection_tag
{
    ...
private:
    M   m_data;
};
 
 

仿函數(shù)

泛化的仿函數(shù) —— 類型隧道(Type Tunneling):是一種通過(guò)訪問墊片使兩個(gè)邏輯相關(guān)但物理不相關(guān)的類型能夠互操作的機(jī)制,墊片允許一個(gè)外部類型通過(guò)一個(gè)接口以一種可識(shí)別且兼容的形式呈現(xiàn)于內(nè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ù)類用于STL算法(VS2008支持的還不錯(cuò)),但當(dāng)我們遇到回調(diào)枚舉API時(shí),局部類是個(gè)非常不錯(cuò)的選擇。

HWND FindChildById(HWND hwndParent, int id)
{
    if (::GetDlgCtrlID(hwndParent) == id)
    {
        return hwndParent;
    }
    else
    {
        struct ChildFind
        {
            ChildFind(HWND hwndParent, int id)
                : m_hwndChild(NULL)
                , m_id(id)
            {
                ::EnumChildWindows(hwndParent, FindProc, reinterpret_cast<LPARAM>(this));
            }
 
            static BOOL CALLBACK FindProc(HWND hwnd, LPARAM lParam)
            {
                ChildFind& find = *reinterpret_cast<ChildFind*>(lParam);
                return (::GetDlgCtrlID(hwnd) == find.m_id) ? 
                    (find.m_hwndChild = hwnd, FALSE) : TRUE;
            }
 
            HWND m_hwndChild;
            int const m_id;
        }find(hwndParent, id);
 
        return find.m_hwndChild;
    }
}
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            欧美成人精品福利| 欧美精品在欧美一区二区少妇| 欧美精品久久久久a| 最新国产の精品合集bt伙计| 欧美成人国产| 你懂的视频一区二区| 亚洲二区视频| 亚洲精品国产系列| 欧美日韩在线播放| 亚洲欧美另类国产| 亚洲欧美日韩国产一区二区| 国产日韩欧美在线一区| 久久亚洲视频| 欧美电影免费观看高清完整版| 亚洲精品乱码视频| 欧美色偷偷大香| 欧美一区二区三区久久精品| 国产毛片一区| 欧美国产日韩一二三区| 欧美人与性动交cc0o| 欧美一区二区三区视频免费播放| 欧美在线视频免费| 亚洲美女在线看| 西西人体一区二区| 亚洲美女色禁图| 午夜宅男久久久| 一本久久综合亚洲鲁鲁| 欧美一区二区三区精品| 99精品国产福利在线观看免费 | 夜夜爽www精品| 亚洲自拍电影| 国产亚洲一区在线| 亚洲国产精品成人| 国产精品日韩在线一区| 免费成人黄色片| 欧美吻胸吃奶大尺度电影| 免费观看一级特黄欧美大片| 国产精品第三页| 欧美成人一区二区三区片免费| 国产精品v日韩精品| 欧美大片免费看| 国产婷婷成人久久av免费高清| 91久久国产精品91久久性色| 国产日韩欧美综合一区| av不卡在线| 亚洲精品系列| 麻豆成人精品| 久久在线91| 国产欧美亚洲一区| 亚洲网站啪啪| 中文av字幕一区| 欧美大片网址| 99精品国产在热久久| 亚洲欧洲日夜超级视频| 黄色国产精品| 亚洲一级二级| 亚洲视频一区二区| 欧美风情在线观看| 欧美高清视频| 韩国av一区| 欧美伊人久久大香线蕉综合69| 夜色激情一区二区| 欧美精品电影| 亚洲精品久久久久久久久久久久| 亚洲国产精品久久久久秋霞不卡| 久久久99精品免费观看不卡| 久久精品中文| 激情成人综合网| 久久天天躁狠狠躁夜夜爽蜜月| 老司机午夜精品| 久久久久久久波多野高潮日日| 亚洲一区二区综合| 亚洲一区尤物| 国产精品久久久久77777| av成人免费在线| 亚洲女同精品视频| 国产精品免费网站在线观看| 亚洲综合成人在线| 久久理论片午夜琪琪电影网| 狠狠v欧美v日韩v亚洲ⅴ| 久久久不卡网国产精品一区| 久久久噜噜噜久久中文字幕色伊伊| 国产手机视频精品| 久久精品久久99精品久久| 美日韩丰满少妇在线观看| 亚洲人成免费| 国产精品成人在线| 亚洲欧美日韩精品一区二区| 久久久欧美一区二区| 亚洲国产va精品久久久不卡综合| 欧美精品一区在线发布| 亚洲一区二区三区三| 美女诱惑黄网站一区| 一区二区高清视频| 国产一区二区三区四区老人| 免费一级欧美片在线播放| 亚洲日本乱码在线观看| 欧美一区二区三区日韩视频| 永久久久久久| 欧美日韩亚洲一区三区| 久久国产精品亚洲va麻豆| 亚洲国产日韩欧美综合久久| 亚洲一区二区三区色| 国产精品综合久久久| 久久精品国产99| 99国产精品久久久久久久| 久久久www成人免费毛片麻豆 | 欧美一区二区三区在线视频| 欧美国产视频日韩| 亚洲自拍偷拍网址| 亚洲国产日日夜夜| 国产欧美日韩亚洲精品| 欧美激情成人在线| 久久精品一本| 亚洲免费在线观看| 亚洲精品免费看| 老司机久久99久久精品播放免费| 亚洲综合三区| 亚洲精选久久| 亚洲福利在线观看| 国产专区一区| 国产精品夜夜嗨| 欧美日韩视频一区二区| 噜噜爱69成人精品| 久久精品中文字幕一区二区三区| aa级大片欧美三级| 亚洲精品乱码久久久久久久久 | 男人天堂欧美日韩| 久久av二区| 亚洲欧美综合v| 亚洲香蕉网站| 一区二区久久| 一本一道久久综合狠狠老精东影业| 影音先锋久久久| 国产一区二区三区网站| 国产精品久久一区二区三区| 欧美日韩成人激情| 奶水喷射视频一区| 蜜桃av一区二区在线观看| 久久亚洲图片| 久久影院午夜论| 久久午夜激情| 久热精品视频| 欧美成人精品在线观看| 欧美不卡激情三级在线观看| 久久婷婷麻豆| 欧美成人情趣视频| 久久偷窥视频| 欧美xxx在线观看| 欧美成人午夜剧场免费观看| 老牛国产精品一区的观看方式| 久久久久久久国产| 毛片一区二区三区| 美女主播视频一区| 欧美岛国在线观看| 欧美精品综合| 欧美午夜大胆人体| 国产免费观看久久| 国产日韩在线看片| 亚洲第一区中文99精品| 亚洲国产成人精品女人久久久| 免费人成网站在线观看欧美高清| 免费亚洲电影| 亚洲另类一区二区| 这里只有精品在线播放| 欧美一区二区视频在线观看2020| 久久精品在线观看| 欧美阿v一级看视频| 国产精品久久婷婷六月丁香| 国内外成人免费视频| 91久久线看在观草草青青| 亚洲毛片av在线| 欧美在线免费视屏| 美日韩在线观看| 99热在线精品观看| 久久久www免费人成黑人精品| 欧美高清在线一区二区| 国产乱子伦一区二区三区国色天香 | 日韩视频永久免费| 亚洲一区尤物| 美女视频一区免费观看| 国产精品国产亚洲精品看不卡15| 国外成人在线| 一区二区三区四区五区在线| 久久国产99| 日韩视频精品| 久久精品国产亚洲a| 欧美日韩123| 亚洲大胆人体视频| 宅男噜噜噜66一区二区66| 久久全国免费视频| 一区二区欧美激情| 欧美88av| 好吊色欧美一区二区三区四区| 亚洲午夜视频在线| 亚洲成色999久久网站| 欧美亚洲一区二区三区| 欧美日韩国产综合在线| 亚洲高清久久网| 久久精品一区二区三区不卡|