2012-05-02 29 views
2

我最近開始將許多現有的類遷移到使用智能指針,並且我有幾個關於如何移植一些我認爲可以從使用智能指針中受益的代碼的問題(但我當然可能是錯的)。我有一個UtlMemBuffer緩衝區管理器類,通過它的頭文件顯示如下。使用智能指針來管理緩衝區

本質上,這個類擁有一個由void */length對組成的緩衝區向量。緩衝區管理是通過一個輔助方法實現的(UtlMemBuffer :: append - 其實現也在下面顯示)。

我想讓這個類使用新的智能指針,這樣可以很好地定義所有權,並且可以最小化重新分配。要使用這個類,客戶端代碼通常將自己的原始指針緩衝區/長度傳遞給構造函數,或者可以調用append。最終,當調用析構函數時,它將釋放它自己的副本,以確保在調用者負責其副本時沒有內存泄漏。我認爲,使用std :: shared_ptr可以避免使用這種類型的雙緩衝區所有權(即調用者將負責新建一個std :: shared_ptr並將它傳遞給在UtlMembuffer

最大的挑戰,因爲我看到它是支持read方法(界面類似於辦法把一個文件的作品),我需要通過原始指針傳回變平的記憶。也許一個更好的設計方法是我回傳一個std :: unique_ptr,我通過展開shared_ptrs的內部集合來創建std :: unique_ptr。我不太確定最好的方法是什麼,儘管我將不得不更改一些當前使用的代碼上課採取這種做法。

如果呼叫者全部通過std :: shared_ptr指針爲ex。我想知道做這種轉換的最佳方法是什麼。

我在這個智能指針業務相當新,所以任何意見將不勝感激。謝謝

/** 
* Smart Buffer class 
*/ 
class UtlMemBuffer 
{ 
public: 
    // default constructor 
    UtlMemBuffer(
     const UtlPath& rBufferPath = UtlPath::ssNull, 
     const void* pBytes = NULL, 
     const size_t& rBufLength = 0); 

    // copy constructor 
    UtlMemBuffer(const UtlMemBuffer& rhs); 

    // move constructor 
    UtlMemBuffer(UtlMemBuffer&& rhs); 

    inline void swap(UtlMemBuffer& rhs) throw() { 
     // enable ADL (not necessary in our case, but good practice) 
     using std::swap; 
     // no need to swap base members - as we are topmost class 
     swap(mBufferPath, rhs.mBufferPath); 
     swap(mBufferLength, rhs.mBufferLength); 
     swap(mBufferBlocks, rhs.mBufferBlocks); 
    } 

    // unified assignment operator 
    UtlMemBuffer& operator=(UtlMemBuffer rhs); 

    // destructor - pure virtual 
    virtual ~UtlMemBuffer(); 

    // add buffer to this one 
    virtual OsStatus append(
     const void* pBytes, 
     const size_t& rBufLength, 
     size_t& rBufLengthWritten); 

    // comparator 
    bool operator==(const UtlMemBuffer& rhs) const; 

    // comparator 
    bool operator<(const UtlMemBuffer& rhs) const; 

    // determine the size of the buffer 
    size_t size() const; 

    /** 
    * comparable interface 
    * 
    * @returns 0 if equal, negative val if less than & 
    *   negative value if greater. 
    */ 
    virtual int compareTo(const UtlMemBuffer& rhs) const; 

    /** copy the bytes into the designated buffer */ 
    OsStatus read (void* pReturnBuffer, 
     const size_t& rMemBufferOffset, 
     const size_t& rReturnBufferLength, 
     size_t& rBytesRead) const; 

    // free existing linked list of blocks 
    void clear(); 

    // path property 
    void setBufferPath(const UtlPath& rBufferPath); 

    UtlPath getBufferPath() const; 

private: 
    typedef std::vector< std::pair<void*, size_t> > MemBufInfo; 

    // the name of the buffer (sort of file name) 
    UtlPath mBufferPath; 

    // this is updated whenever we append data 
    size_t mBufferLength; 

    // here we have a collection of received appends (effectively blocks) 
    MemBufInfo mBufferBlocks; 
}; 

這是輔助方法,它管理對緩衝區塊向量的訪問。如您所見,它重新分配原始指針並將它們存儲在mBufferBlocks成員中。

OsStatus 
UtlMemBuffer::append(const void* pBytes, 
    const size_t& rBufLength, 
    size_t& rBytesWritten) 
{ 
    rBytesWritten = 0; 
    if (pBytes != NULL) { 
     void* block = new char [rBufLength]; 
     memcpy(block, pBytes, rBufLength); 
     mBufferBlocks.push_back(std::make_pair(block, rBufLength)); 
     rBytesWritten = rBufLength; 
     mBufferLength += rBufLength; 
    } 
    return OS_SUCCESS; 
} 

回答

0

如果作者只是簡單地用char *來表示內存字節,就像平常一樣,那麼你可以簡單地存儲向量而不是void */len對。

這就是我可能在這裏做的。假設你不需要對這個內存空間中的對象進行任何實際的破壞,只需將其轉換爲char *並粘貼到一個向量中即可。

+0

嗯,我仍然需要知道每個緩衝區的長度,所以從void *更改爲char *實際上不會產生太大的差別。 void */len或char */len是必要的,以便關注每個緩衝區的長度。不幸的是,數組或char []數組 - 不像它們的Java對象沒有長度信息。 – johnco3

+1

@ johnco3:沒有人建議從'void *'改爲'char *',建議從'void *'改成'std :: vector ',這個_does_知道它自己的長度。 – ildjarn

+0

也許從頭文件中不清楚,但std :: vector >後面的意圖僅僅是一個附加的單獨緩衝區的列表,它們只是簡單地「push_back」追加代碼。該向量中的每個緩衝區都有一個指針和一個長度字段。把它看作是一個單獨的單獨緩衝區的鏈表。例如,如果用戶調用read方法,唯一需要將這些變成向量。我希望這很清楚爲什麼我需要一個單獨的長度字段 - 它與void vs char完全無關。 – johnco3