智能指针的循环引用与解决

智能指针的循环引用

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;
}
posted @ 2020-06-23 12:17  尚修能的技术博客  阅读(2232)  评论(1编辑  收藏  举报