C + + 11 & 14 – Summary of intelligent pointer points

Posted on

People who study c + + all know that there is a pain point in C + +, that is, the management of dynamic memory. In terms of some problems I have experienced, many inexplicable problems are finally found to be caused by improper memory management.

However, some other languages such as Java will not have such problems. Why? Because they have good methods to deal with memory, such as Java’s garbage collection mechanism. Now, we have intelligent pointers in C + + finally.

1. What is a smart pointer

In short, smart pointer is to use an object to manage a resource pointer. At the same time, a counter is used to calculate the number of references to the current pointer object. When the object managing the pointer increases or decreases, the counter also increases or subtracts 1. When the last pointer management object is destroyed, the counter is 1. At this time, when the pointer management object is destroyed, it is also managed by the pointer management object The delete operation is performed on the pointer of the.

Let’s introduce two commonly used smart pointers STD:: shared_ PTR and STD:: weak_ ptr。

1.1 std::shared_ptr

std::shared_ PTR encapsulates the memory allocated dynamically by the new operator and can be copied freely. It is basically the most used intelligent 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 were as follows:

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

The code is interpreted as follows:

std::make_ New operator is called in shared to allocate memory;
The second p1.use_ The reason why count() is displayed as 2 is because the reference object P2 is added. With the end of curly braces, the scope of P2 ends. Therefore, the reference count of P1 changes back to 1. When the main function ends, the scope of P1 ends. At this time, it is detected that the count is 1. When P1 is destroyed, the destructor of P1 is called to delete the allocated memory space;

1.2 std::weak_ptr

std::weak_ What are the characteristics of PTR? And STD:: shared_ The biggest difference of PTR is that it does not cause the intelligent pointer count to increase during the assignment.

weak_ PTR is designed to work with shared_ PTR can work together from a shared_ PTR or another weak_ PTR objects are constructed to obtain the observation weight of resources. But weak_ PTR has no shared resources, and its construction does not increase the pointer reference count. Again, in weak_ When PTR is destructed, it does not reduce the reference count. It is just a silent observer. weak_ PTR does not overload operator * and – >, which is intentional because it does not share pointers and cannot operate on resources, which is the reason why it is weak. If you want to manipulate resources, you must use a very important member function lock() from the observed shared_ PTR gets an available shared_ PTR objects to manipulate resources.

1.2.1 std::shared_ What are the consequences of PTR cross referencing

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; // smart pointer to testb
}; 
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; // smart pointer of testa
};
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 have created a testa and a testb object, but after the whole main function has been run, we have not seen the two objects being destructed. Why?

It turns out that the smart pointer PTR_ PTR is quoted in a_ b. Same PTR_ PTR is also quoted in B_ a. Before the main function exits, PTR_ A and PTR_ The reference count of B is 2. After exiting the main function, the reference count changes to 1, that is, mutual reference.

This is equivalent to saying:

ptr_ A vs PTR_ B said, well, I said PTR_ b. My present condition is that if you release me first, I can release you. This is born and decided by the creator and can not be changed;
ptr_ B also affects PTR_ A said, my conditions are the same. If you release me first, I can release you. What should I do?
It’s true that the problem of mutual reference may lead to memory leakage.

1.2.2 std::weak_ How to solve the problem of mutual reference in PTR

We use STD:: weak on the basis of the above code_ PTR was modified 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()
  {
		////Put STD:: weak_ The PTR type is converted to 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 that:

All objects can be released normally in the end, and the memory in the previous example will not be released;
ptr_aandptr_bBefore exiting in the main function, the reference count is 1, that is, in theTestAandTestBChina vsstd::weak_ptrDoes not cause the count to increase. stayTestBIn a destructor, call thestd::shared_ptr tmp = m_TestA_Ptr.lock(),holdstd::weak_ptrType conversion tostd::shared_ptrType, and thenTestAObject.

1.2.3 std::weak_ PTR supported calls

weak_ PTR < T > W; // empty weak_ PTR can point to objects of type T
weak_ ptr<T> w(shared_ PTR SP); // and SP point to weak of the same object_ PTR, t must be able to convert to the type pointed by sp
W = p; // P can be shared_ PTR or weak_ PTR, after assignment, W and P share the object
w.reset();	//weak_ PTR is set to null
w.use_ Count(); // shared object with W_ The count of PTR
w.expired();	//w.use_ If count() is 0, it returns true, otherwise it returns false
w. Lock(); // w.expired() is true and returns null shared_ Ptr; otherwise, the shared pointing to W is returned_ PTR

1.3 std::unique_ptr

uniqut_ PTR is an intelligent pointer with exclusive ownership of resources, that is, an object resource can only be unique at the same time_ PTR points to.

1.3.1 initialization mode

Using new


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

Through make_ unique


auto pT = make_unique<T>();

Through the move() function

//Up is also an STD:: unique_ PTR < T > pointer
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 assignment, Pt is destroyed and empty
unique_ PTR < T > pT3 (STD:: move (pT2)); // move the copy, pT2 is 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 application examples

#include <iostream>
int main()
{
	std::unique_ptr<int> pInt;
	pInt.reset(new int());
	int *p =  pInt.release (); // release ownership
	//Because of unique_ PTR has STD:: unique_ So it can be used to manage array resources
	std::unique_ptr<int[]> pArray(new int[3]{1,3,3}); 
}

2. Summary of intelligent pointer

As you can see, the smart pointer is actually STD:: shared_ PTR and STD:: unique_ ptr, std::shared_ PTR can have multiple reference objects, but cannot refer to each other, and STD:: unique_ PTR can only have one reference and cannot assign or copy, but can move assignment and copy. STD:: weak_ PTR is actually used for STD:: shared_ PTR supplement, it does not carry on the concrete operation to the object.

Note: shared_ ptr,weak_ ptr,unique_ PTR these are templates, not pointers or anything else.

The above is the detailed content of C + + 11 & 14 – smart pointer summary. For more information about C + + 11 & 14 smart pointer, please pay attention to other related articles in developeppaer!

Leave a Reply

Your email address will not be published.