在c++中用容器來管理動態分配的記憶體,首先想到是會通過標準容器來儲存shared_ptr或者unique_ptr,如下**:
boost庫中專門提供了指標容器儲存指標來管理動態分配的物件。標準庫中vector,list,deque分別有ptr_vector,ptr_list,ptr_deque相對應,並且介面也與標準庫中的容器一致。指標容器與容器+unique_ptr來管理動態分配的記憶體的語義是一致,對容器成員都是獨佔語義,不可複製,只可通過移動來轉移所有權。不同的是指標容器直接操作的是裸指標。#include #include int main()
具體可以看 boost文件說明
指標容器與原容器的介面一直,如下示例
在指標容器會在析構時自動釋放元素的記憶體,所以無需再額外的迭代釋放每個成員的記憶體,如下:#include #include int main()
執行可以看到是沒有記憶體洩漏的。#include #include #define _crtdbg_map_alloc
class ctest
//system("pause");
_crtdumpmemoryleaks();
return 0;
}
在容器析構時是會釋放所有成員的記憶體。那麼直接獲取容器中的成員,就會涉及到所有權問題(誰來釋放記憶體)。如果不注意就會造成重複釋放記憶體的問題,如下示例**:
上面的**會直接崩潰,是因為重複釋放了p指標所指的記憶體(因為tests析構時已經釋放了容器內指標所指的記憶體),示例**是為了演示問題而寫的很直白,在實際的開發中,或許某個介面需要轉入乙個指標,而該指標又儲存在某個指標容器中,那麼此時就應該注意了,不小心就會寫出如示例**的錯誤。int main()
delete p;
p = null;
system("pause");
return 0;
}
見如下**,變數p就直接獲取了tests中第乙個元素的所有權,那麼tests容器中就直接刪除了第乙個元素。
指標容器中有乙個特殊的auto_type,boost文件中對其的描述如下int main()
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方法來轉移所有權。見如下**:
auto_type型別的變數p在將所有權轉移給了p1後,如果不delete p1的話就會造成記憶體洩漏。int main()
}delete p1;
p1 = null;
//system("pause");
_crtdumpmemoryleaks();
return 0;
}
上面提到auto_type型別是不可複製的,所以兩個auto_type型別的變數,不能直接賦值來轉移所有權,見如下**:
上面的**是無法編譯通過的,應該通過ptr_container提供的move函式來進行所有權轉移int main()
p1 = boost::ptr_container::move(p);
在muduo日誌庫中,asynclogging類中通過交換記憶體實現了非同步日誌,在類中分為前端和乙個後端線程,前端用於收集格式化後的日誌,後端線程負責將收集的日誌寫入檔案,前端和後端的資料交換是通過交換記憶體來實現的。這裡不討論其非同步日誌實現思想,主要是學習下其記憶體交換的實現思路。
在asynlogging類中,前端和後端持有兩個塊buffer。buffer的定義如下:
前端執行緒定義的buffer指標成員//buffer的型別
typedef muduo::detail::fixedbufferbuffer;
//指標容器用於儲存多塊buffer
typedef boost::ptr_vectorbuffervector;
//buffer指標,宣告為auto_type型別
typedef buffervector::auto_type bufferptr;
前端快取的初始化,前端持有currentbuffer_和nextbuffer_兩塊記憶體//前端當前使用的快取
bufferptr currentbuffer_;
//前端待用的快取
bufferptr nextbuffer_;
//用於前後端線程交換快取的buffers
buffervector buffers_;
前端執行緒交換快取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兩塊記憶體
如上**,通過指標容器實現記憶體的交換十分優雅,即不會有記憶體拷貝的memecpy操作,也不用專門去考慮記憶體釋放問題,實現的**也十分簡潔易讀。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();
}
相關資料:
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...