Use of weak pointer weak_ptr (detailed explanation)

Use of weak pointer weak_ptr

Errors caused by improper use of shared_ptr lead to weak_ptr

Let's look at the results of running the code and carefully observe the following program:

#include <iostream>  
using namespace std;  
#include <memory>  
  
class B;  
  
class A  
{  
public:  
    shared_ptr<B> ptrA_B;  
public:  
    A()  
    {  
        cout << "调用class A的默认构造函数" << endl;  
    }  
    ~A()  
    {  
        cout << "调用class A的析构函数" << endl;  
    }  
};  
  
class B  
{  
public:  
    shared_ptr<A> ptrB_A;  
public:  
    B()  
    {  
        cout << "调用class B的默认构造函数" << endl;  
    }  
    ~B()  
    {  
        cout << "调用class B的析构函数" << endl;  
    }  
};  
  
int main()  
{  
    shared_ptr<B> ptrB = make_shared<B>();  
    shared_ptr<A> ptrA = make_shared<A>();  
    ptrA->ptrA_B = ptrB;  
    ptrB->ptrB_A = ptrA;  
}  

 

operation result:

 

We can observe from the results:

The class A and class B objects constructed in the heap area are not destroyed, and the memory is not released, which causes a memory leak.

We can observe from the implementation of class A and class B:

class A  
{  
public:  
    shared_ptr<B> ptrA_B;  
public:  
    A()  
    {  
        cout << "调用class A的默认构造函数" << endl;  
    }  
    ~A()  
    {  
        cout << "调用class A的析构函数" << endl;  
    }  
};  
  
class B  
{  
public:  
    shared_ptr<A> ptrB_A;  
public:  
    B()  
    {  
        cout << "调用class B的默认构造函数" << endl;  
    }  
    ~B()  
    {  
        cout << "调用class B的析构函数" << endl;  
    }  
};  

 

Class A contains the reference count pointer to the class B object constructed in the heap area, and class B also contains the reference count pointer to the class A object constructed in the heap area, thus forming the following ring structure:

 

In this case, for the class A object, whenever the life of the class A object ends, the shared_ptr pointer to the class B object constructed in the heap area will call the destructor of class B to end the declaration of the class B object, but at this time The class B object also contains a shared_ptr pointer to the "class A object structured in the heap area", and the destructuring of the class A object must be performed, thus entering an endless loop.

How to prevent this endless loop is a big problem: the weak_ptr pointer starts to work!

The weak_ptr visualization metaphor

I often think of weak_ptr as the younger brother of shared_ptr. We know that shared_ptr can not only access the memory area pointed to, but also control the "life and death" of the pointed area, which means that with the end of the shared_ptr pointer life cycle, the area pointed to by the pointer will also Was released. But weak_ptr is the younger brother of shared_ptr, weak_ptr dare not do this. As the weakest of the smart pointers, weak_ptr can only access the memory area pointed to. When the weak_ptr pointer ends, the memory pointed to is still intact. It is the essential difference between weak_ptr brother and shared_ptr brother.

Since the weak_ptr pointer ends in its life, it will not have any impact on the memory pointed to, so the "abnormal error of the ring reference caused by the shared_ptr mentioned above" will not occur. If you replace the shared_ptr with a weak_ptr structure in the above example, the structure will change:

 

Code example:

#include <iostream>  
using namespace std;  
#include <memory>  
  
class B;  
  
class A  
{  
public:  
    weak_ptr<B> ptrA_B;  // 弱类型指针
public:  
    A()  
    {  
        cout << "调用class A的默认构造函数" << endl;  
    }  
    ~A()  
    {  
        cout << "调用class A的析构函数" << endl;  
    }  
};  
  
class B  
{  
public:  
    weak_ptr<A> ptrB_A;  // 弱类型指针
public:  
    B()  
    {  
        cout << "调用class B的默认构造函数" << endl;  
    }  
    ~B()  
    {  
        cout << "调用class B的析构函数" << endl;  
    }  
};  
  
int main()  
{  
    shared_ptr<B> ptrB = make_shared<B>();  
    shared_ptr<A> ptrA = make_shared<A>();  
    ptrA->ptrA_B = ptrB;  
    ptrB->ptrB_A = ptrA;  
}  

 

operation result:

 

It can be seen from the result that the objects of class A and class B in the heap area have been successfully released.

What happens when the shared_ptr pointer is assigned to the weak_ptr weak type pointer?

We know that the essence of the reference count pointer is "when the memory needs to be destroyed, the count value of the reference count pointer continues to -1 until it is 0, then the memory is destroyed". But we can see from the program running results that "weak_ptr does not affect the count value of the shared_ptr reference count pointer, that is, weak_ptr does not affect the life cycle of the memory pointing to the area". From this point, we can see "Why weak_ptr weak type pointers do not Error that caused the release of the infinite loop (ring problem)".

Therefore, assigning the shared_ptr pointer to the weak_ptr pointer has no effect.

What happens when the weak_ptr pointer is assigned to the shared_ptr pointer?

 

"Assign weak_ptr pointer directly to shared_ptr pointer" is wrong.

We generally treat weak_ptr as a tool for accessing memory content. The advantage of this tool is that "weak_ptr weak pointers will never affect the life cycle of the memory area."

Below we use the weak_ptr member function lock with the return value of shared_ptr to initialize the shared_ptr pointer:

#include <iostream>  
using namespace std;  
#include <memory>  
  
int main()  
{  
    shared_ptr<int> ptr = make_shared<int>(10);  
    weak_ptr<int> ptr1 = ptr; // 必须使用shared_ptr初始化weak_ptr  
    shared_ptr<int> ptr2 = ptr1.lock(); // 利用返回的shared_ptr初始化  
    cout << *ptr2 << endl;  
}  

 

Here, we use the lock member function in weak_ptr to briefly initialize the shared_ptr pointer.

Analysis of weak_ptr member functions

① Expired function: Determine whether the memory space pointed to by the pointer is released / whether the pointer is empty / whether there is still a shared_ptr pointer pointing to the memory space pointed to by weak_ptr

⑴ Function function: judge whether the memory space pointed to by the pointer is released / whether the pointer is empty / whether there is still shared_ptr pointer pointing to the memory space pointed to by weak_ptr

⑵ Code example:

#include <iostream>  
using namespace std;  
#include <memory>  
  
int main()  
{  
    shared_ptr<int> ptr = make_shared<int>(10);  
    weak_ptr<int> ptr1(ptr); // shared_ptr初始化weak_ptr  
    ptr.reset(new int); // 此时,已没有一个shared_ptr指针指向weak_ptr指向的内存区域  
    cout << "是否已没有shared_ptr指针指向该内存区域:" << ptr1.expired() << endl;  
    shared_ptr<int> ptr2 = nullptr;  
    weak_ptr<int> ptr3(ptr2);  
    cout << "weak_ptr指针是否为空:" << ptr3.expired() << endl;  
}  

 

operation result:

 

We can see that:

⑴ Weak_ptr pointer initialization can only rely on shared_ptr pointer assignment;

⑵ When there is no shared_ptr pointer to the memory area pointed to by weak_ptr, the expired member function returns true;

⑶ When the weak_ptr pointer is empty, the expired member function returns true.

② lock member function: return a pointer of type shared_ptr

⑴ Function:

Return a pointer of type shared_ptr

⑵ Code example:

#include <iostream>  
using namespace std;  
#include <memory>  
  
int main()  
{  
    shared_ptr<int> ptr = make_shared<int>(10);  
    weak_ptr<int> ptr1 = ptr; // 必须使用shared_ptr初始化weak_ptr  
    shared_ptr<int> ptr2 = ptr1.lock(); // 利用返回的shared_ptr初始化  
    cout << *ptr2 << endl;  
}  

 

operation result:

 

We see that we can access the data through the returned shared_ptr type pointer, remember: "the weak_ptr pointer does not have a dereference operation".

③ owner_before member function

For details, please see: https://blog.csdn.net/weixin_45590473/article/details/113040456

④ reset, swap, use_count member functions

The usage of these three member functions is the same as in the shared_ptr pointer. Remember one thing: when shared_ptr is assigned to weak_ptr, the reference count value will not change.

For detailed explanation of these three member functions, please refer to: https://blog.csdn.net/weixin_45590473/article/details/113049522

 

Guess you like

Origin blog.csdn.net/weixin_45590473/article/details/113057545