boost中的指標容器

2021-08-15 20:32:20 字數 3905 閱讀 3360

在c++中用容器來管理動態分配的記憶體,首先想到是會通過標準容器來儲存shared_ptr或者unique_ptr,如下**:

#include #include int main()   

boost庫中專門提供了指標容器儲存指標來管理動態分配的物件。標準庫中vector,list,deque分別有ptr_vector,ptr_list,ptr_deque相對應,並且介面也與標準庫中的容器一致。指標容器與容器+unique_ptr來管理動態分配的記憶體的語義是一致,對容器成員都是獨佔語義,不可複製,只可通過移動來轉移所有權。不同的是指標容器直接操作的是裸指標。

具體可以看 boost文件說明

指標容器與原容器的介面一直,如下示例

#include #include int main()

在指標容器會在析構時自動釋放元素的記憶體,所以無需再額外的迭代釋放每個成員的記憶體,如下:

#include #include #define _crtdbg_map_alloc

class ctest

//system("pause");

_crtdumpmemoryleaks();

return 0;

}

執行可以看到是沒有記憶體洩漏的。

在容器析構時是會釋放所有成員的記憶體。那麼直接獲取容器中的成員,就會涉及到所有權問題(誰來釋放記憶體)。如果不注意就會造成重複釋放記憶體的問題,如下示例**:

int main()

delete p;

p = null;

system("pause");

return 0;

}

上面的**會直接崩潰,是因為重複釋放了p指標所指的記憶體(因為tests析構時已經釋放了容器內指標所指的記憶體),示例**是為了演示問題而寫的很直白,在實際的開發中,或許某個介面需要轉入乙個指標,而該指標又儲存在某個指標容器中,那麼此時就應該注意了,不小心就會寫出如示例**的錯誤。

見如下**,變數p就直接獲取了tests中第乙個元素的所有權,那麼tests容器中就直接刪除了第乙個元素。

int main()

指標容器中有乙個特殊的auto_type,boost文件中對其的描述如下

you can think of auto_type as a non-copyable form of std::auto_ptr

我們知道std::auto_ptr是通過複製,賦值來實現的轉移語義,這裡的auto_type是沒有複製語義的,但它有移動語義,也是通過release方法。這跟std::unique_ptr很像也是只有移動語義,也只可通過release方法來轉移所有權。見如下**:

int main()

}delete p1;

p1 = null;

//system("pause");

_crtdumpmemoryleaks();

return 0;

}

auto_type型別的變數p在將所有權轉移給了p1後,如果不delete p1的話就會造成記憶體洩漏。

上面提到auto_type型別是不可複製的,所以兩個auto_type型別的變數,不能直接賦值來轉移所有權,見如下**:

int main()

上面的**是無法編譯通過的,應該通過ptr_container提供的move函式來進行所有權轉移

p1 = boost::ptr_container::move(p);
在muduo日誌庫中,asynclogging類中通過交換記憶體實現了非同步日誌,在類中分為前端和乙個後端線程,前端用於收集格式化後的日誌,後端線程負責將收集的日誌寫入檔案,前端和後端的資料交換是通過交換記憶體來實現的。這裡不討論其非同步日誌實現思想,主要是學習下其記憶體交換的實現思路。

在asynlogging類中,前端和後端持有兩個塊buffer。buffer的定義如下:

//buffer的型別

typedef muduo::detail::fixedbufferbuffer;

//指標容器用於儲存多塊buffer

typedef boost::ptr_vectorbuffervector;

//buffer指標,宣告為auto_type型別

typedef buffervector::auto_type bufferptr;

前端執行緒定義的buffer指標成員

//前端當前使用的快取

bufferptr currentbuffer_;

//前端待用的快取

bufferptr nextbuffer_;

//用於前後端線程交換快取的buffers

buffervector buffers_;

前端快取的初始化,前端持有currentbuffer_和nextbuffer_兩塊記憶體

asynclogging::asynclogging(const string& basename,

size_t rollsize,

int flushinterval)

: flushinterval_(flushinterval),

running_(false),

basename_(basename),

rollsize_(rollsize),

thread_(boost::bind(&asynclogging::threadfunc, this), "logging"),

latch_(1),

mutex_(),

cond_(mutex_),

//初始化快取

currentbuffer_(new buffer),

//初始化快取

nextbuffer_(new buffer),

buffers_()

前端執行緒交換快取

else

else

cond_.notify();

}}後端線程交換快取,後端持有newbuffer1和newbuffer2兩塊記憶體

void asynclogging::threadfunc()

//後端線程被喚醒,後端線程獲得lock鎖

//交換前端正在使用的快取

buffers_.push_back(currentbuffer_.release());

//交換給currentbuffer乙個新的快取

currentbuffer_ = boost::ptr_container::move(newbuffer1);

//將待寫入檔案的日誌交換給bufferstowrite

bufferstowrite.swap(buffers_);

if (!nextbuffer_)

}assert(!bufferstowrite.empty());

if (bufferstowrite.size() > 25)

for (size_t i = 0; i < bufferstowrite.size(); ++i)

if (bufferstowrite.size() > 2)

if (!newbuffer1)

if (!newbuffer2)

bufferstowrite.clear();

output.flush();

} output.flush();

}

如上**,通過指標容器實現記憶體的交換十分優雅,即不會有記憶體拷貝的memecpy操作,也不用專門去考慮記憶體釋放問題,實現的**也十分簡潔易讀。

相關資料:

boost中的智慧型指標

進行本地執行緒管理的 thread specific ptr 指標 可以看這裡 我也沒有怎麼好好看明白呢,就了解了一下,因為用不到啊。如果要通過智慧型指標獲得原始資源指標,則呼叫智慧型指標的 get 即可,而如果要訪問原始資源,智慧型指標過載了 和 操作符,使用起來和原始指標一樣。fread函式的用...

boost中的智慧型指標

進行本地執行緒管理的 thread specific ptr 指標 可以看這裡 我也沒有怎麼好好看明白呢,就了解了一下,因為用不到啊。如果要通過智慧型指標獲得原始資源指標,則呼叫智慧型指標的 get 即可,而如果要訪問原始資源,智慧型指標過載了 和 操作符,使用起來和原始指標一樣。fread函式的用...

boost 容器(簡述)

boost.array和c 中stl中的std vector一樣,都是一樣的操作,沒有什麼不一樣的,唯一不同的是array是乙個定長的陣列 boost.array有一點和c 前面版本不同的是,它是可以向普通陣列一樣直接進行構造的。c 11也開始支援了 int main for auto item a...