[C++11] 迴圈引用
阿新 • • 發佈:2018-12-12
前言
雖然C++11中的智慧指標,一定程度上簡化了C++當中的記憶體管理;但是,shared_ptr<>的使用同時也引出了另一個問題:迴圈引用。
例子
讓我們先來看一段示例程式碼。
#include <iostream> #include <vector> #include <memory> using namespace std; class parent; class children; class parent { public: ~parent() { std::cout << "~parent()" << std::endl; } public: std::shared_ptr<children> child; }; class children { public: ~children() { std::cout << "~children()" << std::endl; } public: std::shared_ptr<parent> parent; }; void Verify() { std::shared_ptr<parent> p(new parent); std::shared_ptr<children> c(new children); p->child = c; c->parent = p; } int main() { std::cout << "Begin" << std::endl; Verify(); std::cout << "Done" << std::endl; }
執行之後,我們可以發現兩個物件都沒有被正常析構。
分析
當我們想要parent物件釋放時,children物件中仍保留了該parent物件的shared_ptr,導致其無法被正常釋放。既然是因為children物件保留了引用,那麼就先釋放children物件唄?很好,parent物件中保留了該children物件的shared_ptr。這樣,我們就陷入了一個死迴圈:迴圈引用。
解決辦法
1. 手動打破"迴圈引用"
void Verify() { std::shared_ptr<parent> p(new parent); std::shared_ptr<children> c(new children); p->child = c; c->parent = p; p->child.reset(); // let it go,手動打破“迴圈引用”這種尷尬的局面; }
2. 使用weak_ptr
weak_ptr僅保持對物件的引用,而不負責具體的資源管理; 但是,相比裸指標而言,weak_ptr提供了expired()介面,方便檢測引用的物件是否已經釋放,這點是裸指標所不具備的。
class parent { public: ~parent() { std::cout << "~parent()" << std::endl; } public: std::shared_ptr<children> child; }; class children { public: ~children() { std::cout << "~children()" << std::endl; } public: std::weak_ptr<parent> parent; // 替換成“弱引用” };