智能指針的循環引用
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;
}