I. shared_ptr Learning
1. Basic concepts of shared_ptr and weak_ptr
- shared_ptr and weak_ptr intelligent pointers are both applications of C++ RAII and can be used for dynamic resource management.
- Shared_ptr is implemented based on the "reference counting" model. Multiple shared_ptrs can point to the same dynamic object and maintain a shared reference counter to record the number of shared_ptr instances that refer to the same object. When the last shared_ptr pointing to a dynamic object is destroyed, it automatically destroys the object it refers to (via the delete operator).
- The default capability of shared_ptr is to manage dynamic memory, but it supports custom Deleter to implement personalized resource release actions.
- weak_ptr is used to solve the cyclic dependency problem of the "reference count" model. weak_ptr points to an object without adding or subtracting the reference counter of that object.
2. Basic operations of shared_ptr
#include <memory>
#include <iostream>
struct Foo {
Foo() { std::cout << "Foo...\n"; }
~Foo() { std::cout << "~Foo...\n"; }
};
struct D {
//Delete Foo object pointed to by p
void operator()(Foo* p) const {
std::cout << "Call delete for Foo object...\n";
delete p;
}
};
int main()
{
// constructor with no managed object
std::shared_ptr<Foo> sh1;
// constructor with object
std::shared_ptr<Foo> sh2(new Foo);
std::shared_ptr<Foo> sh3(sh2);
std::cout << sh2.use_count() << '\n';
std::cout << sh3.use_count() << '\n';
//constructor with object and deleter
std::shared_ptr<Foo> sh4(new Foo, D());
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
Construction method:
1. Constructing by make_shared function
auto s_s = make_shared("hello");
2. Constructing by native pointer
int* pNode = new int(5);
shared_ptr s_int(pNode);
//Get the native pointer
int* pOrg = s_int.get();
3. Constructing shared_ptr by assignment function
4. Overloaded operator - >, operator *, and other auxiliary operations such as unique(), use_count(), get() member methods.
3. The rule of increasing and decreasing the quotation count of intelligent pointer in experiment
The main contents of the experiment are as follows:
1. When shared_ptr variable is destroyed in the life cycle, does the reference count decrease by 1?
2.shared_ptr as a function parameter is divided into pass value and pass reference. How does the reference count change?
2. Does the reference count change when the function return value is shared_ptr?
With these questions in mind, let's look at the code.
#include <iostream>
#include <memory>
using namespace std;
void Func1(shared_ptr<int> a)
{
cout<<"Enter Func1"<<endl;
cout<<"Ref count: "<<a.use_count()<<endl;
cout<<"Leave Func1"<<endl;
}
shared_ptr<int> Func2(shared_ptr<int>& a)
{
cout<<"Enter Func2"<<endl;
cout<<"Ref count: "<<a.use_count()<<endl;
cout<<"Leave Func2"<<endl;
return a;
}
int main()
{
//Construct a pointer aObj1 pointing to an object of type int, reference count + 1
shared_ptr<int> aObj1(new int(10));
cout<<"Ref count: "<<aObj1.use_count()<<endl;
{
//Same as aObj1, but because the life cycle is in parentheses, aObj2 will be destroyed
shared_ptr<int> aObj2 = aObj1;
cout<<"Ref count: "<<aObj2.use_count()<<endl;//Reference Count-1
}
//When calling a function, the parameter is shared_ptr type, the parameter is value-passing type, and the smart pointer reference count + 1
Func1(aObj1);
//When calling a function, the parameter is shared_ptr type, the parameter is passed reference type, and the smart pointer reference count is unchanged.
Func2(aObj1);
shared_ptr<int> aObj3 = Func2(aObj1);//Reference Count + 1
cout<<"Ref count:"<<aObj3.use_count()<<endl;
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
The results are as follows:
Effectively grasp the change rule of quotation count of intelligent pointer, in order to write the program better.
4. shared_ptr application scenarios and usage considerations
4.1 "Sharing Data" between Objects, Object Creation and Destruction "Separation"
4.2 Dynamic objects placed in containers, wrapped in shared_ptr, are more appropriate than unique_ptr.
4.3 When managing "dynamic arrays", you need to develop a Deleter to use the delete [] operator to destroy memory, because shared_ptr does not have a special version for arrays (unique_ptr has a special version for arrays)
5. Thread security of shared_ptr
- The same shared_ptr is read by multiple threads, which is thread-safe.
- The same shared_ptr is written by multiple threads, which is not thread-safe.
- Different shared_ptr s with shared reference counts are written by multiple threads and are thread-safe.
For the third point, we generally adopt:
For an external shared_ptr object passed in a thread, a new construction is made inside the thread, such as shared PTR AObjTmp = outerSharedptrObj;
2. weak_ptr Learning
Let's first figure out why weak_ptr appears, or what problems it exists to solve (existence is reasonable). Ha-ha
class Parent
{
public:
shared_ptr<Child> child;
};
class Child
{
public:
shared_ptr<Parent> parent;
};
shared_ptr<Parent> pA(new Parent);
shared_ptr<Child> pB(new Child);
pA->child = pB;
pB->parent = pA;
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
The smart pointer member variables pointing to the Child class object are stored in the Parent class, and the smart pointer member variables pointing to the Parent class object are also stored in the Child class, which will result in circular reference, which is well explained in C++.
There is no particularly good way to solve the problem of circular references. Generally, weak_ptr is used to replace shared_ptr in places where circular references may occur. Speaking of weak_ptr, let's summarize weak_ptr.
Let's learn about weak_ptr.
weak_ptr points to the memory of the object pointed to by the shared_ptr pointer, but does not own that memory.
However, using the weak_ptr member lock, you can return a shared_ptr object that it points to memory and nullptr when the memory of the object is invalid. Because weak_ptr refers to memory that is directed to shared_ptr, weak_ptr cannot exist independently.
#include <iostream>
#include <memory>
using namespace std;
void Check(weak_ptr<int> &wp)
{
shared_ptr<int> sp = wp.lock(); // Retrieving shared_ptr objects
if (sp != nullptr)
{
cout << "The value is " << *sp << endl;
}
else
{
cout << "Pointer is invalid." << endl;
}
}
int main()
{
shared_ptr<int> sp1(new int(10));
shared_ptr<int> sp2 = sp1;
weak_ptr<int> wp = sp1; // Memory pointing to sp1
cout << *sp1 << endl;
cout << *sp2 << endl;
Check(wp);
sp1.reset();
cout << *sp2 << endl;
Check(wp);
sp2.reset();
Check(wp);
system("pause");
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
The best way to learn programming is to follow it step by step and debug it.
Referring to the above code, we should also be careful when using weak_ptr. We need to judge whether the shared_ptr corresponding to weak_ptr is empty at all times. Weak_ptr does not increase the reference count of shared_ptr.