您好,登錄后才能下訂單哦!
本篇內容介紹了“C++中的循環引用實例”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!
雖然C++11引入了智能指針的,但是開發人員在與內存的斗爭問題上并沒有解放,如果我門實用不當仍然有內存泄漏問題,其中智能指針的循環引用缺陷是最大的問題。
// // main.cpp // test // // Created by 杜國超 on 17/9/9. // Copyright © 2017年 杜國超. All rights reserved. // #include <iostream> #include <memory> #include <vector> using namespace std; class CObjB; class CObjA { public: CObjA() { cout << "CObjA Constructor..." << endl; } ~CObjA() { cout << "CObjA Destructor..." << endl; } shared_ptr<CObjB> m_pb; // 在A中引用B }; class CObjB { public: CObjB() { cout << "CObjB Constructor..." << endl; } ~CObjB() { cout << "CObjB Destructor..." << endl; } shared_ptr<CObjA> m_pa; // 在B中引用A }; int main() { shared_ptr<CObjA> tmpPa = make_shared<CObjA>(); shared_ptr<CObjB> tmpPb = make_shared<CObjB>(); tmpPa->m_pb = tmpPb; tmpPb->m_pa = tmpPa; std::cout << "CObjA referencr num:" << tmpPa.use_count() << endl; std::cout << "CObjB referencr num:" << tmpPb.use_count() << endl; // tmpPa->m_pb.reset(); // tmpPb->m_pa.reset(); // std::cout << "CObjA referencr num:" << tmpPa.use_count() << endl; // std::cout << "CObjB referencr num:" << tmpPb.use_count() << endl; }
我們可以看到在出main函數作用域之前兩個指針指向的內存并沒有釋放(指針指向的對象沒有調用析構函數),我門把當前的引用數打印出來為2這個沒有問題,為什么在函數結束時沒有調用對象的析構函數呢?這就好像多線程之間的死鎖一樣,對象a想要析構但是發現對象b引用了自己所以就等待對象b析構不再引用自己,而b想要析構卻發現對象a引用了自又等待a析構如此就導致兩個指針指向的對象沒有析構釋放內存,這就是循環引用導致的內存問題。
如何證明這個結論呢,我們手動釋放掉兩個對象對對方的引用,就可以解除循環引用關系,正確析構對象了(把注釋部分代碼打開)。運行結果:
我門可以看到,調用reset函數釋放引用關系后,指針的引用計數變為一,等到函數運行結束,兩個shared指針生命周期結束調用析構函數,對象的引用計數減為0,對象內存釋放。
但是如果每次都要手動解除引用來解決循環引用,那么智能指針似乎變成了傻子指針了,這時候還有一個東西能解決,那就是weak_ptr,它不會改變所共享的shared_ptr的引用計數,即使我門可以通過該指針訪問它所指向的對象。
// // main.cpp // test // // Created by 杜國超 on 17/9/9. // Copyright © 2017年 杜國超. All rights reserved. // #include <iostream> #include <memory> #include <vector> using namespace std; class CObjB; class CObjA { public: CObjA() { cout << "CObjA Constructor..." << endl; } ~CObjA() { cout << "CObjA Destructor..." << endl;} void Say() {cout << "CObjA Say..." << endl; } shared_ptr<CObjB> GetPb() { return m_pb.lock(); } public: weak_ptr<CObjB> m_pb; // 在A中引用B }; class CObjB { public: CObjB() { cout << "CObjB Constructor..." << endl; } ~CObjB() { cout << "CObjB Destructor..." << endl; } void Say() {cout << "CObjB Say..." << endl; } shared_ptr<CObjA> GetPa() { return m_pa.lock(); } public: weak_ptr<CObjA> m_pa; // 在B中引用A }; int main() { shared_ptr<CObjA> tmpPa = make_shared<CObjA>(); shared_ptr<CObjB> tmpPb = make_shared<CObjB>(); tmpPa->m_pb = tmpPb; tmpPb->m_pa = tmpPa; std::cout << "CObjA referencr num:" << tmpPa.use_count() << endl; std::cout << "CObjB referencr num:" << tmpPb.use_count() << endl; if (tmpPa->GetPb()!= NULL){ tmpPa->GetPb()->Say(); } if (tmpPb->GetPa()!= NULL){ tmpPb->GetPa()->Say(); } }
這樣就得到我門想要的結果了。最后說一句雖然智能指針帶來了很多方便,但是也要小心使用它仍然有很多坑等著我門,以后再作詳述。
“C++中的循環引用實例”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。