C + + smart pointer

Keywords: C++

typora-copy-images-to: ./

Summary of smart pointer knowledge:

Source cpp, summarize and review by yourself.

Object and memory

Memory distribution:

  • Static memory: local static objects, class static data members, variables defined outside functions.
  • Stack memory: non static objects defined in functions.
  • Memory pool (free space, heap): dynamically allocate objects -- objects allocated at run time.

Memory management for automatic and static objects:

  • Global object, which allocates memory when the program starts and releases memory when the program ends.

  • Local automatic object, allocate memory after entering the defined program block, and release memory after leaving the block.

  • Local static object, which allocates memory before first use and releases memory at the end of the program.

Memory management of dynamically allocated objects:

  • The lifetime has nothing to do with where it is created. The object is destroyed only after it is explicitly released.

  • Directly manage the memory operator new, allocate space in dynamic memory and return a pointer to the object.

  • The direct management memory operator delete accepts a pointer to a dynamic object, destroys the object and frees the associated memory.

  • Problem 1: forgetting to release memory will cause memory leakage.

  • Problem 2: releasing memory under pointer reference memory will refer to pointers of illegal memory.

Smart pointer: it is used to use dynamic objects more safely. Because it is difficult to control the correct release of dynamically allocated objects, the standard library defines two types of smart pointers to help us automatically release an object. The smart pointer is defined in, and the use method is the same as the template.

Directly manage the use of memory new and delete:

new

The memory allocated in the heap is nameless. New cannot name the allocated object, so new will return a pointer to the object. Dynamically allocated objects are initialized by default.

int *ip = new int;//Built in type, initialized to undefined by default.
int *ip2 = new int();//Built in type, value initialized to 0.


//A class type similar to string has a default construction and will be initialized in either form.
string *s = new string; 
string *s2 = new string(); 

//The auto initializer is used to infer the allocation type. Only a single initializer can be provided.
auto p = new auto(obj);

If heap memory is exhausted, use new to throw an std::bad_alloc exception. We use positioning new (placement new) to block. They all exist in the new header file.

int *p = new (nothrow) int ;//Allocation failure returns a null pointer.

delete

The pointer passed to delete either points to dynamically allocated memory or is null. Note: the compiler cannot tell whether the pointer points to a static or dynamically allocated object, and does not know whether the pointing memory has been released.

Built in pointer type management memory:

  • The memory needs to be released by the caller or the function itself, otherwise a memory leak will occur.
  • We'd better set the pointer to null after the delete operation to detect errors.
  • If the same memory is released twice, the heap will be destroyed.

On the second point, because the pointer still points to the address of the released dynamic memory after delete, the pointer is an empty pointer. We can't continue to use this pointer, so we need to set it to null without binding to any object. Meanwhile, delete is only valid for the current pointer, but not for other pointers pointing to the same object.

shared_ptr:

Management mode: multiple pointers are allowed to point to the same object.

Functions for safely allocating and using dynamic memory: make_shared, this function returns a shared_ptr.

//Create a smart pointer
shared_ptr<T> pointer; //Perform default initialization and save a null pointer

//Using make_shared creates a smart pointer, and the passed parameters must match the constructor of the object
shared_ptr<T> pointer2 = make_shared<T>(); //Execute value initialization
shared_ptr<int> pointer3 = make_shared<int>(2); //The smart pointer points to an int object with a value of 2

Copy or assignment operation, each shared_ptr has an associated counter (number of references), which will record how many other shared_ptr points to the same object.

shared_ptr<int> p = make_shared<int>(2); //Object reference count 1
auto r = p; //Assignment operation, object reference count + 1, the result is 2

auto q = make_shared<int>(3); //Number of references to int object with value 3 1
q = r ; // There is no int object with the value of 3. The number of references is 0. The management object is automatically released.

How to automatically destroy management objects: through the destructor, the function will destroy and release the resources allocated by the object. shared_ptr decrements the number of references every time it executes the destructor, so when the number of references is 0, it will destroy the object and free memory.

Automatically release associated memory: shared_ The memory will not be released before PTR is destroyed, so it needs to be destroyed after it is not used. For example, the smart pointer is stored in the container. After the container is rearranged, the smart pointer is no longer used, but the object pointed to by the pointer is still referenced.

Reason for using dynamic memory:

  1. The program doesn't know how many objects it needs to use.
  2. The program does not know the exact type of object.
  3. Programs need to share data among multiple objects.

shared_ptr combined with new:

//The smart pointer is initialized with the pointer returned by new, but it must be explicitly initialized because the built-in pointer cannot be implicitly converted to a smart pointer.
shared_ptr<T> p(new int(1024));	//Explicit conversion

//Common errors, shared_ptr temporary objects are constructed using built-in pointers.
int *i(new int(1024));
void process(shared_ptr<int> (i));
//After the process block is completed, the smart pointer is automatically destructed and i becomes a floating pointer.


//The get function of smart pointer can return a built-in pointer. Considering the above errors, we should not initialize or assign a smart pointer with this pointer, nor delete the built-in pointer.
shared_ptr<int> p2(new int(512));
int *p3 = p2.get();

//The reset operation can make the smart pointer point to the new object.

There are two possibilities for function exit: normal processing end or abnormal exit. When using the built-in pointer to manage memory, if an exception occurs between new and delete, the delete operation will not be performed due to the abnormal exit, so the memory will not be released.

Some classes based on C and C + + do not have good destructors, so we need to release them ourselves. If the content managed by the smart pointer is not the memory allocated by new, you need to pass a delegator according to this class.

shared_ptr<T> P(q,deleter) //p takes over the content pointed to by q, and the deleter is a callable object (deleter)

unique_ptr:

Management mode: monopolize the dynamic object and bind to the pointer returned by new. When it is destroyed, the pointing object is also destroyed, which is the same as shared_ PTRs are different, such as shared copies_ PTR, which is destroyed only decrements the number of references.

Initialization method: and shared_ Similar to PTR, we want to display initialization. But it's different because unique_ptr management mode, we can not use copy and assignment operations.

unique_ptr<int> p(new int(1024));

You can also bind to another unique by releasing / reset_ PTR.

unique_ptr<int> p2(p.release()); //release returns a pointer to the object that p points to

unique_ptr<int> p3(new int(512);
p2.reset(p3.release());			//The reset operation will release the object it originally pointed to
/*                   
p2.release(); //Separate release pointer control cannot release resources. */
delete p2;	//You need to explicitly delete unique using direct memory management_ ptr

unique_ptr can copy or assign a unique to be destroyed_ PTR, for example, can return a unique from the function_ ptr.

Overload unique_ Default deletion of PTR:

unique_ptr<objT,delT> p (new objT,fcn);//The delT object is used to release objT objects. fcn is an object of type delT

weak_ptr:

Management mode: Companion class & weak reference, pointing to shared_ptr manages the object, but does not control the lifetime of the object, so its creation will not affect shared_ptr has an impact on the number of references. Furthermore, it is uncertain whether the object it points to still exists or not.

Initialization method: use a shared_ptr initialization. Or implicitly initialize to null.

shared_ptr<int> p(new int(1024));
weak_ptr<int> p2(p);

Because of its management, we need to confirm unique_ptr is used to check whether the pointing object exists.

if(shared_ptr<int> p = p2.lock()){
	//Using p security to access objects
}

With lock, we can use weak_ptr writes an adjoint pointer class, which will not affect the life cycle of the adjoint class resources, but can check the resources of the adjoint class to prevent access to some resources.

Posted by picker999 on Thu, 23 Sep 2021 01:10:04 -0700