Effective C++ 筆記(8.定製new和delete)
阿新 • • 發佈:2019-01-23
多執行緒環境下的記憶體管理,遭受單執行緒系統不曾有過發挑戰。由於heap是一個可被改動的全域性性資源,因此多執行緒系統充斥著發狂訪問這一類資源的race conditions(競速狀態)出現機會。 如果沒有適當的同步控制(synchronization),一旦使用無鎖(lock-free)演算法或精心防止併發訪問(concurrent access)時,呼叫記憶體例程可能很容易導致管理heap的資料結構內容敗壞。operator new和operator delete只適合來分配單一物件。Arrays所用的記憶體有operator new[]分配出來,並由operator delete[] 歸還。STL容器所使用的heap記憶體是由容器所擁有的分配器物件(allocator objects)管理,不是被new和delete直接管理。條款49:瞭解new-handler的行為設計良好的new-handler函式必須做以下事情:
- 讓更多記憶體可被使用。這便造成operator new內的下一次記憶體分配動作可能成功。實現此策略的一個做法是,程式一開始執行就分配一大塊記憶體,而後當new-handler第一次被呼叫,將它們釋還給程式使用。
- 安裝另一個new-handler。
- 卸除new-handler,也就是null指標傳給set_new_handler。一旦沒有安裝任何new-handler,operator new會在記憶體分配不成功時丟擲異常。
- 丟擲bad_alloc(或派生自bad_alloc)的異常。這樣的異常不會被operator new捕捉,因此會被傳播到記憶體索求處。
- 不返回,通常呼叫abort或exit。
- set_new_handler允許客戶指定一個函式,在記憶體分配無法獲得滿足時被呼叫。
- Nothrow new是一個頗為侷限的工具,因為它只適用於記憶體分配;後繼的建構函式呼叫還是可能丟擲異常。
- 用來檢測運用上的錯誤。
- 為了強化效能。
- 為了收集使用上的統計資料。
- 為了檢測運用錯誤。
- 為了收集動態分配記憶體之使用統計資訊。
- 為了增加分配和歸還的速度。
- 為了降低預設記憶體管理器帶來的空間額外開銷。
- 為了彌補預設分配器中的非最佳齊位(suboptimal alignment)。
- 為了將相關物件成簇集中。
- 為了獲得非傳統的行為。
- 有許多理由需要寫個自定 new和delete,包括改善效能、對heap運用錯誤進行除錯、收集heap使用資訊。
- operator new應該內含一個無窮迴圈,並在其中嘗試分配記憶體,如果它無法滿足記憶體需求,就該呼叫new-handler。它也應該有能力處理0 bytes申請。Class專屬版本則應該處理”比正確大小更大的(錯誤)申請“。
- operator delete應該在收到null指標時不做任何事。Class專屬版本則還應該處理”比正確大小更大的(錯誤)申請“。
- 當你寫一個placement operator new,請確定也寫出了對應的placement operator delete。如果沒有那麼做,你的程式可能會發生隱微而時續的記憶體洩漏。
- 當你宣告placement new和placement delete,請確定不要無意識地遮掩了它們的正常版本。