C語言時期
在C語言中,最常遇到的情況就是忘了釋放記憶體,然後造成Memory Leak的問題。
例如以下這段程式
1 | void LeakDemo(char path1, char path2) |
在上面這段程式裡面,path2就忘了釋放記憶體,然後造成Leak。
這是語言上的侷限,只能靠多檢查source code跟使用工具來減少這種問題。
C++98時期
由於C++有RAII idiom之後,對於釋放記憶體的事情就變得簡單很多了。
1 | struct StackObject { |
而為了一般化,STL裡面時做了一個auto_ptr
,利用Template跟RAII的觀念來管理記憶體。
auto_ptr的問題
如果把auto_ptr侷限於上面的用法,不會遇上什麼問題,一旦要搭配現有的程式碼,當參數傳來傳去,問題就出現了其中最嚴重的問題莫過於
1 | void Test(auto_ptr<int> v) {} |
以上的程式碼,看起來沒什麼問題,不過實際執行就Crash了。
auto_ptr的問題是沒有Copy Semantics,他的Copy Constructur裡面做的是Move的動作。
以下是auto_ptr的Conpy Constructor實作簡化版
1 | template <typename _Tp> |
於是在執行完Test之後,main中的v裡面的pointer就被清空,無法正常使用。
由於這個緣故,STL的各種容器跟演算法,搭配上auto_ptr或多或少都有問題。在經過多次修改之後還是無法修復,於是auto_ptr在C++0x之後就標繼承deprecated了,不建議使用。
由於C++0x引進了Rvalue reference,因此新的unique_ptr就此登場。
unique_ptr
unique_ptr能做的事幾乎跟auto_ptr一樣,除了少數例外。
1 | auto_ptr<int> a(new int); |
不過你也可以利用C++0x新增的Move Semantics,手動進行Move動作。
1 | unique_ptr<int> c(new int); |
靠著C++0x新增的Rvalue Reference,區分出Copy跟Move的差異。看著unique_ptr的實作,他只允許Move Constructor,而不允許Copy Constructor。
1 | template<class _Ty, class _Dx> |
如果要得到更多的Rvalue Refenece的相關內容,請參考這篇Rvalue References: C++0x Features in VC10, Part 2。
unique_ptr還能做些什麼
由於C++0x引進了Move Semantics,連帶的STL所有Container跟Algorithmer都支援Move Semantics了,因此這樣的程式碼就變得可行了。
1 | typedef unique_ptr<char> UniCharPtr; |
在這裡同樣用上了lambda expression,留待有空再寫。
有個手法稱作source and sink idiom
因為有了Move Semantics更容易的實現。
1 | unique_ptr<int> Source() { return unique_ptr<int>(new int); } |
除此之外,還能夠自訂Destructor。
1 | auto del = [](int *p) { |
以及透過partial specialization
來管理一個動態產生的Array。
1 | auto del = [](int p[]) { delete [] p; }; |