C++中的循環(huán)引用
雖然C++11引入了智能指針的,但是開發(fā)人員在與內(nèi)存的斗爭(zhēng)問題上并沒有解放,如果我門實(shí)用不當(dāng)仍然有內(nèi)存泄漏問題,其中智能指針的循環(huán)引用缺陷是最大的問題。

//
// main.cpp
// test
//
// Created by 杜國(guó)超 on 17/9/9.
// Copyright © 2017年 杜國(guó)超. 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函數(shù)作用域之前兩個(gè)指針指向的內(nèi)存并沒有釋放(指針指向的對(duì)象沒有調(diào)用析構(gòu)函數(shù)),我門把當(dāng)前的引用數(shù)打印出來為2這個(gè)沒有問題,為什么在函數(shù)結(jié)束時(shí)沒有調(diào)用對(duì)象的析構(gòu)函數(shù)呢?這就好像多線程之間的死鎖一樣,對(duì)象a想要析構(gòu)但是發(fā)現(xiàn)對(duì)象b引用了自己所以就等待對(duì)象b析構(gòu)不再引用自己,而b想要析構(gòu)卻發(fā)現(xiàn)對(duì)象a引用了自又等待a析構(gòu)如此就導(dǎo)致兩個(gè)指針指向的對(duì)象沒有析構(gòu)釋放內(nèi)存,這就是循環(huán)引用導(dǎo)致的內(nèi)存問題。
如何證明這個(gè)結(jié)論呢,我們手動(dòng)釋放掉兩個(gè)對(duì)象對(duì)對(duì)方的引用,就可以解除循環(huán)引用關(guān)系,正確析構(gòu)對(duì)象了(把注釋部分代碼打開)。運(yùn)行結(jié)果:

我門可以看到,調(diào)用reset函數(shù)釋放引用關(guān)系后,指針的引用計(jì)數(shù)變?yōu)橐?,等到函?shù)運(yùn)行結(jié)束,兩個(gè)shared指針生命周期結(jié)束調(diào)用析構(gòu)函數(shù),對(duì)象的引用計(jì)數(shù)減為0,對(duì)象內(nèi)存釋放。
但是如果每次都要手動(dòng)解除引用來解決循環(huán)引用,那么智能指針?biāo)坪踝兂闪松底又羔樍?,這時(shí)候還有一個(gè)東西能解決,那就是weak_ptr,它不會(huì)改變所共享的shared_ptr的引用計(jì)數(shù),即使我門可以通過該指針訪問它所指向的對(duì)象。
//
// main.cpp
// test
//
// Created by 杜國(guó)超 on 17/9/9.
// Copyright © 2017年 杜國(guó)超. 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();
}
}

這樣就得到我門想要的結(jié)果了。最后說一句雖然智能指針帶來了很多方便,但是也要小心使用它仍然有很多坑等著我門,以后再作詳述。
總結(jié)
以上所述是小編給大家介紹的C++中的循環(huán)引用,希望對(duì)大家有所幫助,如果大家有任何疑問請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
相關(guān)文章
賭你會(huì)懵的C語(yǔ)言指針進(jìn)階數(shù)組場(chǎng)景解析
這篇文章主要為大家介紹了關(guān)于C語(yǔ)言指針進(jìn)階的示例解析,來細(xì)化指針這一部分內(nèi)容,現(xiàn)在著重把一些指針的運(yùn)用情景搬出來康康,如果對(duì)指針盤的不是非常熟練,或者指針還出于入門階段的鐵子請(qǐng)繞道2022-02-02
通過c語(yǔ)言調(diào)用系統(tǒng)curl動(dòng)態(tài)庫(kù)的示例詳解
這篇文章中我們將通過一個(gè)簡(jiǎn)單的示例來講解如何在Ubuntu系統(tǒng)中通過C語(yǔ)言調(diào)用動(dòng)態(tài)庫(kù)(共享庫(kù))的方法,我們將使用libcurl庫(kù),這是一個(gè)基于客戶端的URL傳輸庫(kù),廣泛用于各種程序和應(yīng)用中以訪問網(wǎng)頁(yè)和服務(wù)器數(shù)據(jù),需要的朋友可以參考下2024-03-03
深入探討Linux靜態(tài)庫(kù)與動(dòng)態(tài)庫(kù)的詳解(一看就懂)
本篇文章是對(duì)Linux靜態(tài)庫(kù)與動(dòng)態(tài)庫(kù)進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05
基于OpenCV實(shí)現(xiàn)車道線檢測(cè)(自動(dòng)駕駛 機(jī)器視覺)
無人駕駛技術(shù)是機(jī)器學(xué)習(xí)為主的一門前沿領(lǐng)域,在無人駕駛領(lǐng)域中機(jī)器學(xué)習(xí)的各種算法隨處可見,本文將為大家介紹無人駕駛技術(shù)中的車道線檢測(cè),感興趣的小伙伴可以了解一下2021-11-11
C語(yǔ)言學(xué)生學(xué)籍管理系統(tǒng)課程設(shè)計(jì)
這篇文章主要介紹了C語(yǔ)言學(xué)生學(xué)籍管理系統(tǒng)課程設(shè)計(jì),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-01-01

