智能指針的循環引用與解決


智能指針的循環引用

class Node
{
public:
	shared_ptr<Node> left;
	shared_ptr<Node> right;

	Node(int v)
	{
		this->value = v;
		cout << "Constructor" << endl;
	}
	~Node()
	{
		cout << "Destructor" << endl;
	}
private:
	int value;
};

int main()
{
	shared_ptr<Node> root = std::make_shared<Node>(4);

	root->left = std::make_shared<Node>(2);
	root->right = std::make_shared<Node>(3);

	return 0;
}

上面的程序不會有問題,調用三次構造函數,三次析構函數。

下面增加一個指向父節點的指針。

class Node
{
public:
	shared_ptr<Node> left;
	shared_ptr<Node> right;
	shared_ptr<Node> parent;
	Node(int v)
	{
		this->value = v;
		cout << "Constructor" << endl;
	}
	~Node()
	{
		cout << "Destructor" << endl;
	}
private:
	int value;
};

int main()
{
	shared_ptr<Node> root = std::make_shared<Node>(4);

	root->left = std::make_shared<Node>(2);
	root->left->parent = root;  //強引用計數加1
	root->right = std::make_shared<Node>(3);
	root->right->parent = root;  //強引用計數加1

	cout << "root reference count = " << root.use_count() << endl;
	cout << "left reference count = " << root->left.use_count() << endl;
	cout << "right reference count = " << root->right.use_count() << endl;
	return 0;
}

調用了三次構造函數,但是沒用調用析構函數,這就導致了內存泄漏。
shared_ptr的循環引用定義:
當兩個對象(主體是對象)使用shared_ptr相互引用時,那么當超出范圍時,都不會刪除內存。發生這種情況的原因是shared_ptr在其析構函數中遞減關聯內存的引用計數后,檢查count是否為0,如果不為0,析構函數就不會釋放相應的內存。當出現了循環引用后,就會發現count的值總是不為0。
這里我用goodnotes畫了兩張圖,希望能把這個過程解釋清楚:

那么如何解決這個問題?
使用weak_ptr
下面使用weak_ptr改進二叉樹。weak_ptr不會導致強引用計數增加。

  class Node
{
public:
	shared_ptr<Node> left;
	shared_ptr<Node> right;
	//shared_ptr<Node> parent;
	weak_ptr<Node> parent;
	Node(int v)
	{
		this->value = v;
		cout << "Constructor" << endl;
	}
	~Node()
	{
		cout << "Destructor" << endl;
	}
private:
	int value;
};

int main()
{
	shared_ptr<Node> root = std::make_shared<Node>(4);

	root->left = std::make_shared<Node>(2);
	root->left->parent = root;  //強引用計數加1
	root->right = std::make_shared<Node>(3);
	root->right->parent = root;  //強引用計數加1
	
	cout << "root reference count = " << root.use_count() << endl;
	cout << "left reference count = " << root->left.use_count() << endl;
	cout << "right reference count = " << root->right.use_count() << endl;
	return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM