SoFunction
Updated on 2025-03-02

Smart pointers and garbage collection usage in C++11

In C/C++, we need to manage the dynamic memory area by ourselves. When we write code, we may experience memory management defects in the following 3.

  • Wild pointer: The memory unit has been released, but the pointer to it is still in use
  • Repeat release: Trying to free up the memory unit that has been released
  • Memory leak: Memory units that are no longer in use are not released

The disgusting thing about C++ is that it has pointers, and the writer needs to manage the memory by himself, so there will be many problems with memory. However, in other languages, such as python, java, and C#, there is no pointer concept, which means you don't need to open up and release memory operations. It is precisely because C++ exposes pointers and even exposes rvalue references that C++ runs very quickly.

In order to reduce memory problems in C++, smart pointers have emerged. It is an optimization of C-style pointers. It places the memory release in the destructor of the smart pointer, so that part of the code that manually releases memory can be reduced.

unique_ptr in ++11

#include<memory>
#include<iostream>
using namespace std;
int main()
{
    unique_ptr<int> up1(new int(11));
    unique_ptr<int> up2=up1;//Cannot be compiled
    cout<<*up1<<endl;//11
    unique_ptr<int> up3=move(up1);//Now up3 is the only pointer to the data
    cout<<*up3<<endl;//11
    cout<<*up1<<endl;//Run error
    ();//Release the memory    ();//The memory will not be released repeatedly
    cout<<*up3<<endl;//Run error}

We know that unique_ptr, as its name, means that an object can only be bound by one pointer, and does not allow one object to be bound by multiple unique_ptr at the same time.

Moreover, unique_ptr only has movement semantics, but no copy semantics. Let's look at the above code that unique_ptr<int> up3=move(up1);, in unique_ptr only has movement constructor and movement assignment function, and there is no copy constructor and copy assignment function. So we can only use rvalues ​​to construct or assign unique_ptr.

There is another way to initialize unique_ptr: make_unique<>(). Compared to using new initialization, the former has less memory fragmentation. It is mainly used in modern C++ types, make_unique.

In fact, auto_ptr in C++98 and unique_ptr in C++11 implement the same thing, but in C++98 we do not have the moving semantics, so auto_ptr has the copy constructor and copy assignment function, so such as:
auto_ptr<int> up2=up1; can be compiled, we discarded it in C++11, and auto_ptr is also the reason.

shared_ptr and weak_ptr in ++11

shared_ptr is a shared pointer. It uses reference counting to determine when memory is released. Reference counting means that it counts how many pointers each object points to it. Once an object's reference count is 0, there is no pointer to it, then it is released.
weak_ptr is used to verify the validity of the memory unit pointed to by shared_ptr, and the reference count of the object pointed to by it will not increase.

#include<memory>
#include<iostream>
using namespace std;

void Check(weak_ptr<int>& wp)
{
    shared_ptr<int> sp=();
    if(sp!=nullptr)
        cout<<"still "<<*sp<<endl;
    else
        cout<<"pointer is invalid."<<endl;
}
int main()
{
    shared_ptr<int> sp1=make_shared<int>(22);
    shared_ptr<int> sp2=sp1;
    weak_ptr<int> wp=sp1;

    cout<<*sp1<<endl;
    cout<<*sp2<<endl;
    Check(wp);

    ();
    cout<<*sp2<<endl;
    Check(wp);

    ();
    Check(wp);

}

22
22
still 22
22
still 22
pointer is invalid.

3. Garbage recycling

Although smart pointers can help users effectively manage heap memory, they still need to explicitly declare smart pointers, and memory management methods that do not require pointers at all will be more pleasing. This method is the garbage collection mechanism. There is no need to open up and release memory operations when writing code. These operations are automatically implemented by the compiler. This intelligent solution is the garbage collection mechanism.

Unfortunately, C++ does not support garbage collection mechanisms.

There are 4 ways to collect garbage

Reference counting method
In fact, it is the same as shared_ptr, which means that the object is released once the number of references is 0. Python uses this solution, but this solution is not good and it is relatively inefficient. Once the object is created or there is a pointer pointing to it, the reference must be calculated at this time, and it cannot solve the problem of "ring reference"

Tag-Clear
This method is to have a root object, which manages all objects, traverses each object in turn, marks the areas they refer to, and then after the traversal is completed, all unmarked areas are released. The disadvantage of this solution is that there will be a large number of memory fragments.

Tag-organization
It is based on the mark-clearing scheme. After marking, no longer traversal and release garbage, but all marked areas are tied to the left, thus reducing memory fragmentation

Tag-Copy
It divides the memory space into two pieces: From and to. At the beginning, memory is allocated from the From space. Once the From memory is full, all live objects in the From space are copied into the to space, and they are all tied to the left, and then the From and to characters are exchanged.

Unfortunately, C++11 has not yet publicly supported garbage collection, but some libraries and limited compilers support some garbage collection functions.

int main()
{
    int *p=new int;
    p+=10;
    p-=10;
    *p=10;
}

In the above code, once p points to other regions, if your compiler supports garbage collection, such as the reference timing method, once p moves to other regions, the opened new int space will be released. What is more dangerous is that this space will be used by other threads. At this time, if p points back to the original place, then p is a wild pointer.

In order to prevent the new int space from being recycled by the garbage collector, one of our solutions is:

int main()
{
    int *p=new int;
    declare_reachable(p);
    p+=10;
    p-=10;
    *p=10;
}

The declare_reachable function here explicitly tells the garbage collector that you should not release this space

This is the article about the use of smart pointers and garbage recycling in C++11. For more related C++11 smart pointers and garbage recycling content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!