亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > C++ > 正文

養成良好的C++編程習慣之內存管理的應用詳解

2020-01-26 16:16:25
字體:
來源:轉載
供稿:網友

開篇導讀        

  雖然本系列文章定位為科普讀物,但本座相信它們不但適合新手們學習借鑒,同時也能引發老鳥們的反思與共鳴。歡迎大家提出寶貴的意見和反饋 ^_^

  在開篇講述本章主要內容之前,本座首先用小小篇幅論述一下一種良好的工作習慣 ―― 積累、提煉與求精。在工作和學習的過程中,不斷把學到的知識通過有效的方式積累起來,形成自己的知識庫,隨著知識量的擴大,就會得到從量變到質變的提升。另外還要不斷地對知識進行提煉,隨著自己知識面的擴大以及水平的提升,你肯定會發現原有知識庫存在著一些片面、局限、笨拙甚至錯誤。這時,就需要你有精益求精精的態度和毅力對知識庫進行優化整理。

  也許以上這些各位都曾想過去實施,也明白其中的道理,但是自己就是給自己各種堂而皇之的借口不花時間去做。這樣說吧,技術之路不好走,這個行業有兩項基本要求:1、對軟件開發工作本身有很大興趣;2、耐得住寂寞。兩者缺一不可,否則還是趁年輕早點轉行吧,要不轉做軟件行業的銷售、產品或者管理也行,總之就不要做開發 ^_^

--------------------------------------------------------------------------------

內存管理相關問題

  一提起 C/C++ 的內存管理,大部分人腦海里都立刻涌出 new / delete / malloc / free 等幾個恐怖的單詞吧?的確,C/C++ 的手工內存管理是它們區別于其他語言的一大特點,也像一道屏障立在那些想從其它語言轉向 C/C++ 的人士身前。由此也引起各大論壇對 “C++ 人氣低落”和“是否應該引入垃圾回收機制”等相關話題的劇烈爭論。本座一直無視這些爭論,其實并非本座不關心 C++ 的發展與命運,相反,本座十分關心。雖然從現在的眼光看來,無論是 C++ 身上有多少硬傷,C++ 委員會的大爺們和 C++ 編譯器廠商的大佬們如何扯貓尾。畢竟最愛就是最愛,殘缺美也是美,不解釋。本座之所以不關心這些爭論,原因是因為看透了,一門語言就像一種人生,是有生命周期的,沒落只是快慢的問題,舊事物總會被新事物取代,這是客觀規律不可避免。秦始皇最終不也是沒找到長生不老的仙丹么?只要曾經發光發熱過,在還有價值的時候能為大眾所用就已經無憾了。本座在此還要申明一種態度:本座并不排斥任何語言,相反,本座對新語言的誕生非常感興趣。會去了解它們的特點,看看它們能幫助解決哪方面的問題。正如這幾年,由于工作需要,本座用得最多的是 Java 和一些動態語言(它們的確能解決很多問題),而 C/C++ 卻沒再用了。

  嗯,扯遠了,我們還是回到正題吧。說起 C/C++ 的內存管理似乎令人望而生畏,滿屏的 new / delete / malloc / free,OutPut 窗口無盡的 Memory Leak 警告,程序詭異的 0X00000004 指針異常,仿佛回到那一年我們一起哭過的日子,你 Hold 得住嗎?其實,現實并沒有你想的那么糟糕。只要你付出一點點,花一點點心思,沒錯!就一點點而已 ―― 用 C++ 類封裝內存訪問,就會解決你大部分的煩惱,讓你受益終身。以 Windows 程序為例,主要有以下幾種內存管理方式:

•虛擬內存(Virtual Memory)
•默認堆和私有堆(Process Heap & Private Heap)
•內存映射文件(File Mapping)
•進程堆棧(Heap,其實就是用 malloc() 或 默認的 new 操作符在 Process Heap 里一小塊一小塊地割肉 ^_^)
•棧(Stack,內存由調用者或被調用者自動管理)
   今天我們的主題是封裝,至于每種內存模型的概念和 API 的使用方式在這里就不講了,Google 一下就知道。其實用 C++ 封裝上述前 4 種內存訪問的原理都差不多,就是在構造函數或其他操作函數中分配內存,然后再在析構函數中確保內存被正確釋放。虛擬內存、默認堆和私有堆的操作方式相似,這里就不一一展示了,有興趣的朋友可以參考本座前幾天發表的那篇無人問津的文章:《C++ 封裝私有堆(Private Heap)》,哎!下面對內存映射文件的封裝也只稍作介紹、我們主要討論的是使用頻率最高的 malloc() 和 new 的封裝。

--------------------------------------------------------------------------------

 內存映射文件

  下面的代碼把 File Mapping 句柄以及從 File Mapping 映射出來的內存分別封裝到 CFileMapping 和 CShareMemory 中,可以直接使用 CShareMemory 可以創建一個 File Mapping 以及映射 File Mapping 的內存。

復制代碼 代碼如下:

class CFileMapping
{
public:
    CFileMapping(   
                    LPCTSTR lpszName,
                    DWORD dwMaximumSizeLow,
                    DWORD dwMaximumSizeHigh                            = 0,
                    HANDLE hFile                                    = INVALID_HANDLE_VALUE,
                    DWORD flProtect                                    = PAGE_READWRITE,
                    LPSECURITY_ATTRIBUTES lpFileMappingAttributes    = NULL
                )
    {
        m_hMap    = ::CreateFileMapping    (
                                            hFile,
                                            lpFileMappingAttributes,
                                            flProtect,
                                            dwMaximumSizeHigh,
                                            dwMaximumSizeLow,
                                            lpszName
                                        );
        ASSERT(IsValid());
    }

    ~CFileMapping()
    {
        if(IsValid())
            VERIFY(::CloseHandle(m_hMap));
    }

    LPVOID ViewMap    (
                        DWORD dwNumberOfBytesToMap,
                        DWORD dwFileOffsetLow,
                        DWORD dwFileOffsetHigh    = 0,
                        DWORD dwDesiredAccess    = FILE_MAP_ALL_ACCESS
                    )
    {
        return ::MapViewOfFile    (
                                    m_hMap,
                                    dwDesiredAccess,
                                    dwFileOffsetHigh,
                                    dwFileOffsetLow,
                                    dwNumberOfBytesToMap
                                );
    }

    BOOL UnViewMap(LPCVOID lpBaseAddress)
    {
        return ::UnmapViewOfFile(lpBaseAddress);
    }

    operator HANDLE    ()    {return m_hMap;}
    BOOL IsValid    ()    {return m_hMap != NULL;}

private:
    HANDLE m_hMap;

    DECLARE_PRIVATE_COPY_CONSTRUCTOR(CFileMapping)
};

class CShareMemory
{
public:
    CShareMemory(DWORD dwSize, LPCTSTR lpszName = NULL)
    : m_fm(lpszName, dwSize)
    {
        ASSERT(dwSize > 0);
    }

    ~CShareMemory()
    {
        for(set<ULONG_PTR>::const_iterator it = m_set.begin(); it != m_set.end(); ++it)
        {
            LPVOID pV = (LPVOID)*it;
            ASSERT(pV);

            m_fm.UnViewMap(pV);
        }

        m_set.clear();
    }

    LPVOID Alloc(DWORD dwNumberOfBytesToMap, DWORD dwFileOffsetLow)
    {
        LPVOID pV = m_fm.ViewMap(dwNumberOfBytesToMap, dwFileOffsetLow);

        if(pV) m_set.insert((ULONG_PTR)pV);

        ASSERT(pV);
        return pV;
    }

    BOOL Free(LPCVOID lpBaseAddress)
    {
        ASSERT(lpBaseAddress);

        set<ULONG_PTR>::iterator it = m_set.find((ULONG_PTR)lpBaseAddress);

        if(it != m_set.end())
            m_set.erase(it);

        return m_fm.UnViewMap(lpBaseAddress);
    }

private:

    CFileMapping    m_fm;
    set<ULONG_PTR>    m_set;

    DECLARE_PRIVATE_COPY_CONSTRUCTOR(CShareMemory)
};


 

  細心的朋友一定會發覺其實這樣封裝是有缺點的:首先,CShareMemory 只能做內存共享,不能映射到真實文件(hFile 永遠為 INVALID_HANDLE_VALUE);第二,可以對 CShareMemory 的 Alloc() 和 Free() 方法進一步封裝,利用封裝類的析構函數自動調用 Free(),這樣就可以完全消除 “set<ULONG_PTR> m_set” 這個屬性了;第三,CFileMapping 也可以把文件句柄一起封裝進來,這樣,從 CreateFile() 到 CreateFileMapping() 都受控了。這個不完美的封裝就權當反面教材吧 ^_^

--------------------------------------------------------------------------------

malloc() 系列函數

  很多人都建議,在 C++ 中盡量用 new 操作符取代 malloc(),因為 new 類型安全,自動調用構造函數和析構函數等等。關于這點本座略有異議,在某些情形下 malloc() 其實比 new 更好使,效率方面我們可以不計較(幾乎所有編譯器的 new 操作符都用 malloc() 分配內存),從事過偏底層開發的人都清楚,我們避免不了處理 row data(如:socket 的收發緩沖區等)數據,這類數據是非常適合使用 malloc() 的,用 new 分配的內存還要停頓下來想想到底是用 delete、delete[]、::delete、::delete[] 中的哪個釋放,malloc() 分配的內存想都不用想,free() 包打天下,何況人家有 realloc() 可以方便地重新調整內存,你有沒有 “renew” 呢?總之一句話,malloc() 的確是有存在的必要,就看接下來我們如何封裝它了,請看代碼:

復制代碼 代碼如下:

// T                 : 數據類型(內置類型或結構體)
// MAX_CACHE_SIZE    : 預申請內存的最大數目,以 sizeof(T) 為單位,如果該值設置合理,對于
//                     需要動態遞增緩沖區的 buffer 來說能大大提高效率
template<class T, size_t MAX_CACHE_SIZE = 0>
class CBufferPtrT
{
public:
    explicit CBufferPtrT(size_t size = 0, bool zero = false)    {Reset(); Malloc(size, zero);}
    explicit CBufferPtrT(const T* pch, size_t size)    {Reset(); Copy(pch, size);}
    // 拷貝構造函數要分兩種情形
    CBufferPtrT(const CBufferPtrT& other)    {Reset(); Copy(other);}
    template<size_t S> CBufferPtrT(const CBufferPtrT<T, S>& other)    {Reset(); Copy(other);}

    ~CBufferPtrT() {Free();}

    T* Malloc(size_t size = 1, bool zero = false)
    {
        Free();
        return Alloc(size, zero, false);
    }

    T* Realloc(size_t size, bool zero = false)
    {
        return Alloc(size, zero, true);
    }

    void Free()
    {
        if(m_pch)
        {
            free(m_pch);
            Reset();
        }
    }

    template<size_t S> CBufferPtrT& Copy(const CBufferPtrT<T, S>& other)
    {
        if((void*)&other != (void*)this)
            Copy(other.Ptr(), other.Size());

        return *this;
    }

    CBufferPtrT& Copy(const T* pch, size_t size)
    {
        Malloc(size);

        if(m_pch)
            memcpy(m_pch, pch, size * sizeof(T));

        return *this;
    }

    // 動態擴大 buffer
    template<size_t S> CBufferPtrT& Cat(const CBufferPtrT<T, S>& other)
    {
        if((void*)&other != (void*)this)
            Cat(other.Ptr(), other.Size());

        return *this;
    }

    // 動態擴大 buffer
    CBufferPtrT& Cat(const T* pch, size_t size = 1)
    {
        size_t pre_size = m_size;
        Realloc(m_size + size);

        if(m_pch)
            memcpy(m_pch + pre_size, pch, size * sizeof(T));

        return *this;
    }

    template<size_t S> bool Equal(const CBufferPtrT<T, S>& other) const
    {
        if((void*)&other == (void*)this)
            return true;
        else if(m_size != other.Size())
            return false;
        else if(m_size == 0)
            return true;
        else
            return (memcmp(m_pch, other.Ptr(), m_size * sizeof(T)) == 0);
    }

    bool Equal(T* pch) const
    {
        if(m_pch == pch)
            return true;
        else if(!m_pch || !pch)
            return false;
        else
            return (memcmp(m_pch, pch, m_size * sizeof(T)) == 0);
    }

    T*    Ptr()    {return m_pch;}
    const T*    Ptr()    const    {return m_pch;}
    T&    Get(int i)    {return *(m_pch + i);}
    const T&    Get(int i)    const    {return *(m_pch + i);}
    size_t    Size()    const    {return m_size;}
    bool    IsValid()    const    {return m_pch != 0;}
    // 啊哈,竟然是類型安全的
    operator    T*    ()    {return Ptr();}
    operator const    T*    ()    const    {return Ptr();}
    // 哇塞,竟然還支持索引訪問
    T& operator    []    (int i)    {return Get(i);}
    const T& operator    []    (int i)    const    {return Get(i);}
    bool operator    ==    (T* pv)    const    {return Equal(pv);}
    template<size_t S> bool operator    ==    (const CBufferPtrT<T, S>& other)    {return Equal(other);}
    // 賦值操作符要分兩種情形
    CBufferPtrT& operator    =    (const CBufferPtrT& other)    {return Copy(other);}
    template<size_t S> CBufferPtrT& operator    =    (const CBufferPtrT<T, S>& other)    {return Copy(other);}

private:
    void Reset()    {m_pch = 0; m_size = 0; m_capacity = 0;}
    size_t GetAllocSize(size_t size)    {return max(size, min(size * 2, m_size + MAX_CACHE_SIZE));}

    T* Alloc(size_t size, bool zero = false, bool is_realloc = false)
    {
        if(size >= 0 && size != m_size)
        {
            size_t rsize = GetAllocSize(size);
            if(size > m_capacity || rsize < m_size)
            {
                m_pch = is_realloc                            ?
                    (T*)realloc(m_pch, rsize * sizeof(T))    :
                   (T*)malloc(rsize * sizeof(T))            ;

                if(m_pch || rsize == 0)
                {
                    m_size        = size;
                    m_capacity    = rsize;
                }
                else
                    Reset();
            }
            else
                m_size = size;
        }

        if(zero && m_pch)
            memset(m_pch, 0, m_size * sizeof(T));

        return m_pch;
    }

private:
    T*        m_pch;
    size_t    m_size;
    size_t    m_capacity;
};

// 常用 buffer 類型的 typedef
typedef CBufferPtrT<char>            CCharBufferPtr;
typedef CBufferPtrT<wchar_t>        CWCharBufferPtr;
typedef CBufferPtrT<unsigned char>    CByteBufferPtr;
typedef CByteBufferPtr                CBufferPtr;

#ifdef _UNICODE
    typedef CWCharBufferPtr            CTCharBufferPtr;
#else
    typedef CCharBufferPtr            CTCharBufferPtr;
#endif

  嗯。這里要解釋一下為何需要兩個拷貝構造函數和賦值操作符重載,首先,編譯器為不同的模板參數生成不同的類,也就是說:CBufferPtrT<int, 1> 和 CBufferPtrT<int, 2> 被看作是不同的類,另外,C++ 編譯器為每個類提供了提供了拷貝構造函數和賦值操作符重載的默認實現(淺拷貝)。因此,上述的第一組拷貝構造函數和賦值操作符重載是改寫編譯器的默認實現,第二組拷貝構造函數和賦值操作符重載是處理其它類到本類的轉換。

  本座對這個封裝灰常滿意(唯一美中不足的就是 cnblogs 的編輯器太坑爹了,把代碼弄亂 ^_^),它并非只是一個普通的 malloc() 封裝,完全能可以把它看作是一種“支持索引訪問的類型安全的動態緩沖區”。如果把它放在一個 socket 通信類中作為成員屬性,充當跨越多個線程和多個方法訪問的接收緩沖區和發送緩沖區的角色就最適合不過了(當然要自己做同步了)。大家可以調試一下下面的測試例子,了解一下它的用法:

復制代碼 代碼如下:

測試用例
 int _tmain(int argc, _TCHAR* argv[])
 {
     CBufferPtr buffer;

     unsigned char c1    = 'X';
     unsigned char pc1[] = "123";
     unsigned char pc2[] = "abc";
     buffer.Cat(&c1);
     buffer.Cat(pc1, 3);
     buffer.Cat(pc2, 3);

     CBufferPtrT<unsigned char, 10> buffer2 = buffer;
     buffer2.Cat(buffer);
     buffer2.Realloc(0);

     unsigned char* pc = buffer;
     const unsigned char& c = buffer[5];
     buffer[5] = 'O';

     short i1    = 0x7FFF;
     short pi0[] = {9,9,9};
     short pi1[] = {1,2,3};
     short pi2[] = {4,5,6};
     short pi3[] = {8,8,8};

     CBufferPtrT<short, 10> bufferS(pi0, 3);

     bufferS.Cat(&i1);
     bufferS.Cat(pi1, 3);
     bufferS.Cat(pi2, 3);
     bufferS.Cat(pi3, 3);

     CBufferPtrT<short, 5> bufferS2;
     bufferS2.Malloc(4);

     bufferS2 = bufferS;
     bufferS2.Realloc(30);

     CBufferPtrT<int> bufferI(5, true);

     for(size_t i = 0; i < bufferI.Size(); i++)
         bufferI[i] = i *10;

     bufferI.Malloc();
     bufferI[0] = 123;

     // 下面這行編譯不通過,正好說明這個類是類型安全的
 // bufferI = bufferS;

     return 0;
 }


--------------------------------------------------------------------------------

new & delete

  一說到 new 的封裝大家立馬想到的就是智能指針吧!沒錯,就是智能指針。但 STL 提供的 auto_ptr 缺陷很多,首先使用起來不方便,竟然連這種寫法都不支持:“std::auto_ptr<int> pi = new int;”,天理何在?。「珊薜氖遣恢С謹到M指針(需要 delete[]),另外如果某些類重載了 new 操作符的話使用它也有很多問題的,還有其它的很多缺點(我忘記了 ^_^)。不過,C++0x 似乎對智能指針作了重大改進,已經有支持引用計數的智能指針了,但不知是否解決數組指針和區分 delete 與 ::delete 的問題(本座沒實測,要是您知道麻煩告訴一聲 ^_^)。無論如何,下面代碼列出的智能指針支持區分 delete / delete[] / ::delete / ::delete[]。算是 auto_ptr 的改良(也沒有使用引用計數),文章篇幅太長了,測試用例就不發了,各位看官自行嘗試吧:

復制代碼 代碼如下:

/************************************************************************/
/*                       smart_ptr 單實體或數組智能指針                    */
/************************************************************************/

template<class _Ty>
struct simple_deleter
{
    static void delete_ptr(_Ty* pv) {delete pv;}
};

template<class _Ty>
struct global_simple_deleter
{
    static void delete_ptr(_Ty* pv) {::delete pv;}
};

template<class _Ty>
struct array_deleter
{
    static void delete_ptr(_Ty* pv) {delete[] pv;}
};

template<class _Ty>
struct global_array_deleter
{
    static void delete_ptr(_Ty* pv) {::delete[] pv;}
};

template<class _Ty, class _Deleter>
class smart_ptr
{
public:
    smart_ptr(_Ty* _Ptr = 0)                    : _Myptr(_Ptr)                {}
    smart_ptr(smart_ptr<_Ty, _Deleter>& _Right)    : _Myptr(_Right.release())    {}

    ~smart_ptr()
    {
        reset();
    }

    smart_ptr<_Ty, _Deleter>& reset(_Ty* _Ptr = 0)
    {
        if (_Ptr != _Myptr)
        {
            if(_Myptr)
                _Deleter::delete_ptr(_Myptr);

            _Myptr = _Ptr;
        }

        return *this;
    }

    smart_ptr<_Ty, _Deleter>& reset(smart_ptr<_Ty, _Deleter>& _Right)
    {
        if (this != &_Right)
            reset(_Right.release());

        return *this;
    }

    _Ty* release()
    {
        _Ty* _Ptr    = _Myptr;
        _Myptr        = 0;

        return _Ptr;
    }

    smart_ptr<_Ty, _Deleter>& operator = (_Ty* _Ptr)                        {return reset(_Ptr);}
    smart_ptr<_Ty, _Deleter>& operator = (smart_ptr<_Ty, _Deleter>& _Right)    {return reset(_Right);}

    bool is_valid        ()    const    {return _Myptr != 0;}
    _Ty& operator *        ()    const    {return *_Myptr;}
    _Ty* get            ()    const    {return _Myptr;}
    _Ty* operator ->    ()    const    {return _Myptr;}
    operator _Ty*        ()    const    {return _Myptr;}

private:
    template<class _Other> smart_ptr<_Ty, _Deleter>                    (const smart_ptr<_Ty, _Other>&);
    template<class _Other> smart_ptr<_Ty, _Deleter>&    reset        (const smart_ptr<_Ty, _Other>&);
    template<class _Other> smart_ptr<_Ty, _Deleter>&    operator =    (const smart_ptr<_Ty, _Other>&);

    template<class _Other> smart_ptr<_Ty, _Deleter>                    (const smart_ptr<_Other, _Deleter>&);
    template<class _Other> smart_ptr<_Ty, _Deleter>&    reset        (const smart_ptr<_Other, _Deleter>&);
    template<class _Other> smart_ptr<_Ty, _Deleter>&    operator =    (const smart_ptr<_Other, _Deleter>&);

protected:
    _Ty* _Myptr;
};


/************************************************************************/
/*                    smart_simple_ptr 單實體智能指針                      */
/************************************************************************/

template<class _Ty>
class smart_simple_ptr : public smart_ptr<_Ty, simple_deleter<_Ty>>
{
public:
    smart_simple_ptr(_Ty* _Ptr = 0)                                    : smart_ptr(_Ptr)    {}
    smart_simple_ptr(smart_simple_ptr<_Ty>& _Right)                    : smart_ptr(_Right)    {}
    smart_simple_ptr(smart_ptr<_Ty, simple_deleter<_Ty>>& _Right)    : smart_ptr(_Right)    {}

    smart_simple_ptr<_Ty>& operator = (smart_ptr<_Ty, simple_deleter<_Ty>>& _Right)
    {return (smart_simple_ptr<_Ty>&)__super::operator = (_Right);}

    smart_simple_ptr<_Ty>& operator = (smart_simple_ptr<_Ty>& _Right)
    {return (smart_simple_ptr<_Ty>&)__super::operator = (_Right);}

    smart_simple_ptr<_Ty>& operator = (_Ty* _Ptr)
    {return (smart_simple_ptr<_Ty>&)__super::operator = (_Ptr);}

private:
    template<class _Other> smart_simple_ptr<_Ty>                (const smart_ptr<_Ty, _Other>&);
    template<class _Other> smart_simple_ptr<_Ty>&    operator =    (const smart_ptr<_Ty, _Other>&);

    template<class _Other> smart_simple_ptr<_Ty>                (const smart_simple_ptr<_Other>&);
    template<class _Other> smart_simple_ptr<_Ty>&    operator =    (const smart_simple_ptr<_Other>&);
};

/************************************************************************/
/*           smart_gd_simple_ptr 單實體智能指針 (使用全局 delete)          */
/************************************************************************/

template<class _Ty>
class smart_gd_simple_ptr : public smart_ptr<_Ty, global_simple_deleter<_Ty>>
{
public:
    smart_gd_simple_ptr(_Ty* _Ptr = 0)                                        : smart_ptr(_Ptr)    {}
    smart_gd_simple_ptr(smart_gd_simple_ptr<_Ty>& _Right)                    : smart_ptr(_Right)    {}
    smart_gd_simple_ptr(smart_ptr<_Ty, global_simple_deleter<_Ty>>& _Right)    : smart_ptr(_Right)    {}

    smart_gd_simple_ptr<_Ty>& operator = (smart_ptr<_Ty, global_simple_deleter<_Ty>>& _Right)
    {return (smart_gd_simple_ptr<_Ty>&)__super::operator = (_Right);}

    smart_gd_simple_ptr<_Ty>& operator = (smart_gd_simple_ptr<_Ty>& _Right)
    {return (smart_gd_simple_ptr<_Ty>&)__super::operator = (_Right);}

    smart_gd_simple_ptr<_Ty>& operator = (_Ty* _Ptr)
    {return (smart_gd_simple_ptr<_Ty>&)__super::operator = (_Ptr);}

private:
    template<class _Other> smart_gd_simple_ptr<_Ty>                    (const smart_ptr<_Ty, _Other>&);
    template<class _Other> smart_gd_simple_ptr<_Ty>&    operator =    (const smart_ptr<_Ty, _Other>&);

    template<class _Other> smart_gd_simple_ptr<_Ty>                    (const smart_gd_simple_ptr<_Other>&);
    template<class _Other> smart_gd_simple_ptr<_Ty>&    operator =    (const smart_gd_simple_ptr<_Other>&);
};

/************************************************************************/
/*                   smart_array_ptr 數組智能指針                        */
/************************************************************************/

template<class _Ty>
class smart_array_ptr : public smart_ptr<_Ty, array_deleter<_Ty>>
{
public:
    smart_array_ptr(_Ty* _Ptr = 0)                                : smart_ptr(_Ptr)    {}
    smart_array_ptr(smart_simple_ptr<_Ty>& _Right)                : smart_ptr(_Right)    {}
    smart_array_ptr(smart_ptr<_Ty, array_deleter<_Ty>>& _Right)    : smart_ptr(_Right)    {}

    smart_array_ptr<_Ty>& operator = (smart_ptr<_Ty, array_deleter<_Ty>>& _Right)
    {return (smart_array_ptr<_Ty>&)__super::operator = (_Right);}

    smart_array_ptr<_Ty>& operator = (smart_array_ptr<_Ty>& _Right)
    {return (smart_array_ptr<_Ty>&)__super::operator = (_Right);}

    smart_array_ptr<_Ty>& operator = (_Ty* _Ptr)
    {return (smart_array_ptr<_Ty>&)__super::operator = (_Ptr);}

private:
    template<class _Other> smart_array_ptr<_Ty>                    (const smart_ptr<_Ty, _Other>&);
    template<class _Other> smart_array_ptr<_Ty>&    operator =    (const smart_ptr<_Ty, _Other>&);

    template<class _Other> smart_array_ptr<_Ty>                    (const smart_array_ptr<_Other>&);
    template<class _Other> smart_array_ptr<_Ty>&    operator =    (const smart_array_ptr<_Other>&);
};

/************************************************************************/
/*          smart_gd_array_ptr 數組智能指針 (使用全局 delete)          */
/************************************************************************/

template<class _Ty>
class smart_gd_array_ptr : public smart_ptr<_Ty, global_array_deleter<_Ty>>
{
public:
    smart_gd_array_ptr(_Ty* _Ptr = 0)                                        : smart_ptr(_Ptr)    {}
    smart_gd_array_ptr(smart_gd_array_ptr<_Ty>& _Right)                        : smart_ptr(_Right)    {}
    smart_gd_array_ptr(smart_ptr<_Ty, global_array_deleter<_Ty>>& _Right)    : smart_ptr(_Right)    {}

    smart_gd_array_ptr<_Ty>& operator = (smart_ptr<_Ty, global_array_deleter<_Ty>>& _Right)
    {return (smart_gd_array_ptr<_Ty>&)__super::operator = (_Right);}

    smart_gd_array_ptr<_Ty>& operator = (smart_gd_array_ptr<_Ty>& _Right)
    {return (smart_gd_array_ptr<_Ty>&)__super::operator = (_Right);}

    smart_gd_array_ptr<_Ty>& operator = (_Ty* _Ptr)
    {return (smart_gd_array_ptr<_Ty>&)__super::operator = (_Ptr);}

private:
    template<class _Other> smart_gd_array_ptr<_Ty>                (const smart_ptr<_Ty, _Other>&);
    template<class _Other> smart_gd_array_ptr<_Ty>&    operator =    (const smart_ptr<_Ty, _Other>&);

    template<class _Other> smart_gd_array_ptr<_Ty>                (const smart_gd_array_ptr<_Other>&);
    template<class _Other> smart_gd_array_ptr<_Ty>&    operator =    (const smart_gd_array_ptr<_Other>&);
};


 --------------------------------------------------------------------------------

 后記

• 對于內存管理,其實還有一種情形還沒講的,就是如何優雅地管理 vetor、list、map 這類容器中的指針,這個話題留到以后討論 STL 時再詳細闡述吧。
•在本座的代碼中基本上看不到 free / delere 這類單詞(new 則是有的 ―― 給智能指針賦值的時候 ^_^),就本座的經驗而言,封裝如果利用得當確實能減少很多麻煩,使代碼更清晰,有條理,降低錯誤發生幾率。
•當然了,封裝并不是萬能,它不能解決所有問題,關鍵是靠個人的專注與細心。
•本座碼字提出自己的觀點,旨在拋磚引玉,激發大家思考如何培養良好的編程習慣,不是權威,更不能盡信。最實在的知識應該來自個人最直接的體驗。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
日韩在线视频线视频免费网站| 成人精品在线视频| 国产欧美一区二区三区视频| 97超级碰碰碰| 丁香五六月婷婷久久激情| 91精品在线观| 国产精品视频99| 亚洲国产又黄又爽女人高潮的| 5252色成人免费视频| 清纯唯美日韩制服另类| 久久99久久99精品免观看粉嫩| 红桃视频成人在线观看| 欧洲s码亚洲m码精品一区| 91色中文字幕| 北条麻妃久久精品| 亚洲缚视频在线观看| 久久99热这里只有精品国产| 成人精品aaaa网站| 日本久久久久久久久| 日韩二区三区在线| 国产成人精品网站| 欧美性猛交xxxx富婆弯腰| 两个人的视频www国产精品| 色婷婷综合成人av| 精品美女永久免费视频| 91色在线视频| 亚洲男子天堂网| 亚洲国产精品美女| 91免费国产视频| 精品综合久久久久久97| 色综合色综合久久综合频道88| 欧美亚洲午夜视频在线观看| 超碰97人人做人人爱少妇| 在线看日韩欧美| 成人乱人伦精品视频在线观看| 亚洲欧美日韩国产中文专区| 成人精品视频久久久久| 久久久久国产精品一区| 97久久精品人人澡人人爽缅北| 亚洲国产精品嫩草影院久久| 欧美一乱一性一交一视频| 最近日韩中文字幕中文| 亚洲成人精品久久久| 在线观看国产精品日韩av| 精品国内自产拍在线观看| 国内精品小视频在线观看| 日韩欧美亚洲国产一区| 亚洲免费视频网站| 久久人人爽亚洲精品天堂| 国产小视频91| 精品无人区太爽高潮在线播放| 成人免费黄色网| 日韩欧美中文免费| 欧美午夜精品久久久久久浪潮| 日本精品性网站在线观看| 色在人av网站天堂精品| 欧美视频裸体精品| 高跟丝袜一区二区三区| 国产精品成人免费视频| 国产免费一区二区三区在线能观看| 91夜夜揉人人捏人人添红杏| 97视频在线观看免费高清完整版在线观看| 浅井舞香一区二区| 欧美区在线播放| 日韩av在线看| 亚洲第一中文字幕在线观看| 欧美性极品少妇精品网站| 欧美激情a在线| 中文字幕亚洲图片| 欧美激情二区三区| 91成人福利在线| 成人久久一区二区三区| 亚洲欧美综合区自拍另类| 美女999久久久精品视频| 欧美成人午夜免费视在线看片| 亚洲毛茸茸少妇高潮呻吟| 欧美性xxxx在线播放| 亚洲大胆人体av| 国产午夜精品全部视频播放| 一区二区三区视频免费在线观看| 久久国产精品亚洲| 热久久这里只有精品| 国产精品日日摸夜夜添夜夜av| 欧美中文在线免费| 欧美电影免费观看高清完整| 日韩毛片在线看| 久久久亚洲天堂| 久久久久久久久亚洲| 国产精品久久久久免费a∨大胸| 欧美在线观看视频| 国语自产精品视频在线看| 久久精品久久精品亚洲人| 亚洲精品网址在线观看| 欧美丰满少妇xxxxx做受| 亚洲欧洲在线观看| 亚洲精品国产精品久久清纯直播| 国产欧美最新羞羞视频在线观看| 国产亚洲精品va在线观看| 91日本视频在线| 精品国产乱码久久久久酒店| 亚洲乱码国产乱码精品精| 一本一本久久a久久精品综合小说| 国a精品视频大全| 精品久久久久久亚洲精品| 精品国产欧美一区二区三区成人| 久久精品国产成人精品| 中文字幕精品影院| 国产日韩视频在线观看| 久久网福利资源网站| 欧美国产日韩在线| 69视频在线播放| 91美女福利视频高清| 欧美刺激性大交免费视频| 日韩av成人在线观看| 欧美亚州一区二区三区| 亚洲白虎美女被爆操| 日韩精品免费看| 日韩一级裸体免费视频| 日韩中文字在线| 91在线观看免费网站| 欧美夫妻性生活xx| 国产精品综合网站| 日日噜噜噜夜夜爽亚洲精品| 亚洲精品小视频| 日韩专区在线观看| 亚洲黄色免费三级| 亚洲人成电影网| 国产精品国内视频| 在线观看国产精品91| 久久精品国产一区二区三区| 国内精品久久久久久影视8| 国产在线视频91| 91在线观看免费高清| 欧美色播在线播放| 久久影视电视剧凤归四时歌| 亚洲天堂网在线观看| 亚洲欧美日本另类| 日韩电影中文字幕在线观看| 亚洲自拍偷拍色片视频| 欧美俄罗斯乱妇| 日本欧美精品在线| 日本欧美一二三区| 国内免费精品永久在线视频| 中文字幕精品网| 久久精品中文字幕电影| 秋霞午夜一区二区| 亚洲精品免费一区二区三区| 欧美日韩国产区| 色伦专区97中文字幕| 欧美三级欧美成人高清www| 狠狠躁天天躁日日躁欧美| 国产精品久久久91| 国产精品小说在线| 精品日韩美女的视频高清| 国产成人精品视频在线| 91九色综合久久| 国产精品福利久久久| 亚洲tv在线观看| 国产精品专区第二| 国产精品劲爆视频| 韩国视频理论视频久久| 国产午夜精品视频| 91福利视频在线观看| 一区二区三区视频免费在线观看|