c++1114 Summary of smart pointer points

  • 2020-09-28 09:01:41
  • OfStack

Those of you who study c++ know that there is a pain point in c++, which is the management of dynamic memory. As far as I have experienced some problems, many puzzling problems are finally found to be caused by improper memory management.

But other languages like java don't have this problem. Why? Because they have very good ways of handling memory, like java's garbage collection mechanism.

1. What are smart Pointers

Say simply, smart Pointers pointer object is used to manage a resource, at the same time with reference to the current pointer object of computation of a counter number, when the management object of pointer to increase or decrease, counter correspondingly plus 1 or minus 1, when finally a management object is destroyed, counter to 1, at this point in the destruction of pointer management object at the same time, also for Pointers for delete operation management object managed by the pointer.

Here we introduce two commonly used smart Pointers std::shared_ptr and std::weak_ptr.

1.1 std::shared_ptr

std::shared_ptr wraps the dynamically allocated memory of the new operator, which can be copied freely and is basically the most used 1 smart pointer type.

Here is a code example:


#include <memory>
#include <iostream>
class Test
{
public:
  Test()
  {
    std::cout << "Test()" << std::endl;
  }
  ~Test()
  {
    std::cout << "~Test()" << std::endl;
  }
};
int main()
{
  std::shared_ptr<Test> p1 = std::make_shared<Test>();
  std::cout << "1 ref:" << p1.use_count() << std::endl;
  {
    std::shared_ptr<Test> p2 = p1;
    std::cout << "2 ref:" << p1.use_count() << std::endl;
  }
  std::cout << "3 ref:" << p1.use_count() << std::endl;
  return 0;
}

The results are as follows:

[

Test()
1 ref:1
2 ref:2
3 ref:1
~Test()

]

The code interpretation is as follows:

std::make_shared called new operator to allocate memory;
Second p1. use_count () are displayed as 2, because of the increased p2 reference object, and with the end of the curly braces, p2 scope over, so p1 reference counting back to 1, and with the main function end, p1 is over, the scope of the detected count to 1, it would be as well as destruction of p1 call p1 destructor delete off before allocated memory space;

1.2 std::weak_ptr

std:: What are the features of weak_ptr? The biggest difference from std::shared_ptr is that it does not cause the smart pointer count to increase during assignment.

weak_ptr is designed to work with shared_ptr and can be constructed from 1 shared_ptr or another weak_ptr object to obtain the observation rights of the resource. But weak_ptr has no Shared resource, and its construction does not increase the pointer reference count. Similarly, weak_ptr destruct does not result in a reduction in reference counts, it is just a quiet observer. weak_ptr does not overload operator* and - > This is special because it does not share Pointers and cannot manipulate resources, which is why it is weak. To manipulate the resource, you must use a very important member function, lock(), to get one of the available shared_ptr objects from the observed shared_ptr to manipulate the resource.

1.2.1 What are the consequences of std::shared_ptr cross-references

The code is as follows:


#include <memory>
#include <iostream>
class TestB;
class TestA
{
public:
  TestA()
  {
    std::cout << "TestA()" << std::endl;
  }
  void ReferTestB(std::shared_ptr<TestB> test_ptr)
  {
    m_TestB_Ptr = test_ptr;
  }
  ~TestA()
  {
    std::cout << "~TestA()" << std::endl;
  }
private:
  std::shared_ptr<TestB> m_TestB_Ptr; //TestB Smart pointer 
}; 
class TestB
{
public:
  TestB()
  {
    std::cout << "TestB()" << std::endl;
  }
  void ReferTestB(std::shared_ptr<TestA> test_ptr)
  {
    m_TestA_Ptr = test_ptr;
  }
  ~TestB()
  {
    std::cout << "~TestB()" << std::endl;
  }
  std::shared_ptr<TestA> m_TestA_Ptr; //TestA Smart pointer 
};
int main()
{
  std::shared_ptr<TestA> ptr_a = std::make_shared<TestA>();
  std::shared_ptr<TestB> ptr_b = std::make_shared<TestB>();
  ptr_a->ReferTestB(ptr_b);
  ptr_b->ReferTestB(ptr_a);
  return 0;
}

Operation results:

[

TestA()
TestB()

]

As you can see, in the above code, we created 1 OBJECT for TestA and 1 object for TestB, but after the entire main function runs, we don't see the two objects being destructed. Why?

It turns out that the smart pointer ptr_a refers to ptr_b, and ptr_b also refers to ptr_a. Before the exit of main function, the reference counts of ptr_a and ptr_b are both 2, and after the exit of main function, the reference counts are both 1, that is, mutual references.

This is equivalent to saying:

ptr_a said to ptr_b, ah, I say ptr_b, my condition now is that you release me first, and Then I can release you. This is nature, the creator decided, it cannot be changed;
ptr_b also said to ptr, "My conditions are the same. You release me first, and Then I can release you. What should I do?
Right? Everybody's right. The problem with cross-referencing is that it can lead to conflicting release conditions, which can eventually lead to memory leaks.

1.2.2 std::weak_ptr How to solve the problem of cross-references

We used std::weak_ptr to modify the above code, as follows:


#include <iostream>
#include <memory>
class TestB;
class TestA
{
public:
  TestA()
  {
    std::cout << "TestA()" << std::endl;
  }
  void ReferTestB(std::shared_ptr<TestB> test_ptr)
  {
    m_TestB_Ptr = test_ptr;
  }
  void TestWork()
  {
    std::cout << "~TestA::TestWork()" << std::endl;
  }
  ~TestA()
  {
    std::cout << "~TestA()" << std::endl;
  }
private:
  std::weak_ptr<TestB> m_TestB_Ptr;
};
class TestB
{
public:
  TestB()
  {
    std::cout << "TestB()" << std::endl;
  }
  void ReferTestB(std::shared_ptr<TestA> test_ptr)
  {
    m_TestA_Ptr = test_ptr;
  }
  void TestWork()
  {
    std::cout << "~TestB::TestWork()" << std::endl;
  }
  ~TestB()
  {
		//// the std::weak_ptr Type into std::shared_ptr type 
    std::shared_ptr<TestA> tmp = m_TestA_Ptr.lock();
    tmp->TestWork();
    std::cout << "2 ref a:" << tmp.use_count() << std::endl;
    std::cout << "~TestB()" << std::endl;
  }
  std::weak_ptr<TestA> m_TestA_Ptr;
};
int main()
{
  std::shared_ptr<TestA> ptr_a = std::make_shared<TestA>();
  std::shared_ptr<TestB> ptr_b = std::make_shared<TestB>();
  ptr_a->ReferTestB(ptr_b);
  ptr_b->ReferTestB(ptr_a);
  std::cout << "1 ref a:" << ptr_a.use_count() << std::endl;
  std::cout << "1 ref b:" << ptr_a.use_count() << std::endl;
  return 0;
}

Operation results:

[

TestA()
TestB()
1 ref a:1
1 ref b:1
~TestA::TestWork()
2 ref a:2
~TestB()
~TestA()

]

preview
From the above code running results, we can see:

All objects are eventually released normally, and there is no problem with the memory not being freed in the previous example.
ptr_a and ptr_b In the main function, the reference counts are all 1 until exit, that is, before exit TestA and TestB In the std::weak_ptr Does not result in an increase in the count. in TestB In the destructor, call std::shared_ptr tmp = m_TestA_Ptr.lock(), the std::weak_ptr Type into std::shared_ptr Type, and then yes TestA Object.

1.2.3 std::weak_ptr supported calls


weak_ptr<T> w;	// empty weak_ptr You can point to type 1 T The object of 
weak_ptr<T> w(shared_ptr sp);	// with sp Pointing to the same object weak_ptr, T It has to be able to convert to theta sp Type of pointing 
w = p;	//p Can be shared_ptr or weak_ptr And after the assignment w and p The Shared object 
w.reset();	//weak_ptr Set to null 
w.use_count();	// with w Shared object shared_ptr The count of 
w.expired();	//w.use_count() for 0 It returns true Otherwise return false
w.lock();	//w.expired() for true , returns empty shared_ptr; Otherwise return the point w the shared_ptr

1.3 std::unique_ptr

uniqut_ptr is a smart pointer with exclusive ownership of resources, that is, one object resource can only be pointed to by one unique_ptr at the same time.

1.3.1 Initialization method

Using new


T *pT = new T();
std::unique_ptr<T> up1(pT);

Through make_unique


auto pT = make_unique<T>();

By the move() function


//up Is also 1 a std::unique_ptr<T> Pointer to the 
unique_ptr<T> up1 = std::move(up); 

1.3.2 unique_ptr cannot be copied or copied


unique_ptr<T> up(new T()); //ok
unique_ptr<T> up1(up); //error, can not be copy
unique_ptr<T> up2 = up; //error, can not be assigned

1.3.3 unique_ptr can move assignments or copies


unique_ptr<T> pT(new T());
unique_ptr<T> pT2 = std::move(pT);	// Move the assignment, at this point pT Destroyed and empty 
unique_ptr<T> pT3(std::move(pt2)); // Move copy, at this point pT2 Destroyed and empty 

1.3.4 unique_ptr can be used as the return value of the function


unique_ptr<T> GetPtr(); //function getthe unique pointer
unique_ptr<T> pT = GetPtr(); // ok

1.3.5 Usage examples


#include <memory>
#include <iostream>
class TestB;
class TestA
{
public:
  TestA()
  {
    std::cout << "TestA()" << std::endl;
  }
  void ReferTestB(std::shared_ptr<TestB> test_ptr)
  {
    m_TestB_Ptr = test_ptr;
  }
  ~TestA()
  {
    std::cout << "~TestA()" << std::endl;
  }
private:
  std::shared_ptr<TestB> m_TestB_Ptr; //TestB Smart pointer 
}; 
class TestB
{
public:
  TestB()
  {
    std::cout << "TestB()" << std::endl;
  }
  void ReferTestB(std::shared_ptr<TestA> test_ptr)
  {
    m_TestA_Ptr = test_ptr;
  }
  ~TestB()
  {
    std::cout << "~TestB()" << std::endl;
  }
  std::shared_ptr<TestA> m_TestA_Ptr; //TestA Smart pointer 
};
int main()
{
  std::shared_ptr<TestA> ptr_a = std::make_shared<TestA>();
  std::shared_ptr<TestB> ptr_b = std::make_shared<TestB>();
  ptr_a->ReferTestB(ptr_b);
  ptr_b->ReferTestB(ptr_a);
  return 0;
}
0

2. Summary of smart Pointers

As you can see, the smart pointer is std::shared_ptr and std::unique_ptr, std::shared_ptr can have more than one reference, but can't refer to each other, while std::unique_ptr can only have one reference, can't assign or copy, but can move assignment and copy, std::weak_ptr is actually a complement to std::shared_ptr, which does not perform specific operations on objects.

Note: shared_ptr,weak_ptr,unique_ptr these are templates, not Pointers or anything else.

So that's c++11 & 14- Smart pointer points summary details, more on c++11 & The information of 14 smart Pointers please pay attention to other related articles on this site!


Related articles: