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

            Imperfect C++ 讀書(shū)筆記(六)

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

            返回值生命期

            在本章,我們通過(guò)考察5個(gè)不完美的將整形轉(zhuǎn)換為字符串類(lèi)型的技術(shù),探討下C++中返回值生命期的各種問(wèn)題和陷阱,最后總結(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()開(kāi)銷(xiāo)的10%。然而,也并非完美無(wú)缺。首先,它不算十分簡(jiǎn)潔:需要用戶(hù)提供緩沖區(qū)的指針和緩沖區(qū)的長(zhǎng)度。其次,更重要的一點(diǎn),用戶(hù)提供的緩沖區(qū)長(zhǎng)度有可能是錯(cuò)誤的。如果太小,也許還能在調(diào)試版中引發(fā)一個(gè)斷言,如果大于緩沖區(qū)真實(shí)的長(zhǎng)度,就有可能發(fā)生緩沖區(qū)溢出。

            2. TSS

              利用TSS(Thread-Specific Storage,線(xiàn)程相關(guān)存儲(chǔ)),我們可以提供一個(gè)線(xiàn)程安全的內(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)字符類(lèi)型了,需要顯式地參數(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)用的問(wèn)題,可以運(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è)同一類(lèi)整型到字符串的轉(zhuǎn)換。32表示“安全”和棧大小之間的一個(gè)折衷,相對(duì)于方案2給用戶(hù)提供了一種虛假的安全感,所以并不推薦使用。

            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)度是足夠的。該方案是線(xiàn)程安全的,且不需要進(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è)代理類(lèi),返回該代理類(lèi)的實(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)后指針)問(wèn)題的困擾。它需要在表達(dá)式中立即使用返回值,而不應(yīng)該保留到以后使用。

            在這里,我們發(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)存塊而已。

             

            多維數(shù)組

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

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

            1. 每一個(gè)模板都維護(hù)一個(gè)指向一維內(nèi)存快的指針,其他存放的是邏輯上N維的數(shù)組元素。
            2. 每一個(gè)類(lèi)都有一個(gè)dimension_element_type成員類(lèi)型,該成員的類(lèi)型對(duì)一維數(shù)組類(lèi)其實(shí)就是value_type,對(duì)高維數(shù)組類(lèi)就是比它低一維的數(shù)組模板。
            3. begin()和end()方法返回的迭代器表示整個(gè)多維數(shù)組所有的元素集合區(qū)間,這便意味著,可以是使用同一stl算法(如 std::for_each())來(lái)處理不同維數(shù)的數(shù)組。
            4. 一個(gè)數(shù)組模板不但自身能夠作為一個(gè)完整的多維數(shù)組類(lèi),而且還能夠作為比它更高維的數(shù)組模板的子數(shù)組切片。作為完整多維數(shù)組類(lèi)時(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 ();
             
            // 訪問(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ù)組。

            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ù) —— 類(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>());

            局部類(lèi)

            雖然某些老版本的編譯器不支持局部仿函數(shù)類(lèi)用于STL算法(VS2008支持的還不錯(cuò)),但當(dāng)我們遇到回調(diào)枚舉API時(shí),局部類(lèi)是個(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;
                }
            }
            久久青草国产精品一区| 天天爽天天狠久久久综合麻豆| 久久精品无码午夜福利理论片 | 伊人久久大香线蕉影院95| 91久久香蕉国产熟女线看| 偷偷做久久久久网站| 91精品国产高清久久久久久国产嫩草| 久久久久久A亚洲欧洲AV冫 | 女人香蕉久久**毛片精品| 婷婷久久综合九色综合九七| 浪潮AV色综合久久天堂| 久久99精品国产99久久6| 亚洲中文字幕无码久久综合网 | 亚洲中文字幕无码久久精品1 | 72种姿势欧美久久久久大黄蕉| 色99久久久久高潮综合影院| 日本强好片久久久久久AAA| 四虎久久影院| 国产99久久久久久免费看| 97久久久久人妻精品专区| 久久精品国产色蜜蜜麻豆| 久久国产免费| 久久影院亚洲一区| 99热精品久久只有精品| 国产成人久久精品一区二区三区 | 香蕉久久av一区二区三区| 久久久久久免费视频| 免费一级欧美大片久久网| 国产精品99久久久久久宅男| 国产高潮国产高潮久久久| 激情伊人五月天久久综合| 亚洲AV无码一区东京热久久| 一本久久a久久精品综合香蕉| 免费一级欧美大片久久网| 麻豆久久| 亚洲精品国产字幕久久不卡| 亚洲AV无码1区2区久久| 精品久久8x国产免费观看| 精品久久一区二区三区| 亚洲国产精品久久66| 久久无码AV中文出轨人妻|