C++ dynamic memory

dynamic memory

Dynamic memory and smart pointers

  • C++ uses newand deletemanages dynamic memory, but sometimes it is difficult to ensure the accuracy of memory allocation or release. In response to this problem, the standard library provides smart pointers, which can automatically release the pointed object, shared_ptrallowing multiple pointers to point to the same object.

shared_ptr

  • When copying or assigning, each shared_ptrwill record how many other shared_ptrobjects point to the same object. It can be considered that each shared_ptrhas an associated counter, usually called a reference count . When one is copied shared_ptr, the reference count will be incremented, and shared_ptrwhen an object is destroyed , its corresponding reference count is decremented.
  • shared_ptrAutomatic destruction of managed objects is achieved through the object's destructor .
  • shared_ptrThe associated memory is also automatically freed.
  • A common reason to use dynamic memory is to allow multiple objects to share the same state. The commonly used container is to generate a new container by copying. If multiple containers are allowed to share the same elements, the cost of copying can be saved, which can be realized by using smart pointers.
  • code

    void test()
    {
        // 使用智能指针的方式,sps会首先指向一个默认初始化的string
        shared_ptr<string> sps;
        if (sps && sps->empty())
        {
            *sps = "233";
            cout << *sps << endl;
        }
    
        shared_ptr<int> p1 = make_shared<int>(42);
        shared_ptr<string> p2 = make_shared<string>(10, 'A'); // make_shared可以提供特定类型的初始化参数
        shared_ptr<int> p3 = make_shared<int>();
        cout << *p1 << endl;
        cout << *p2 << endl;
        cout << *p3 << endl;
    
        shared_ptr<vector<string>> pstr1 = make_shared < vector<string> >(3, "2333");
        cout << pstr1.use_count() << endl; // 1次
        shared_ptr<vector<string>> pstr2 = pstr1;
        pstr2->push_back("test"); // 指向同一位置,所以修改pstr2,pstr1也会改变
        for_each(pstr1->begin(), pstr1->end(), [](const string& str){ cout << str << endl; });
        cout << pstr1.use_count() << endl; // 2次
    
    }
    

direct memory management

  • Use new and delete to manage memory directly
  • new is used to dynamically allocate memory, and delete is used to release memory space
  • When new, if the application for memory space fails, bad_allocan exception will be reported, so it can be used nothrow. When the application for memory space fails, a null pointer is returned without an exception being reported.
  • new and delete need to be used in pairs, otherwise the memory space applied for cannot be released.
  • There are several major problems with using new and delete to manage memory
    • Often forget to delete memory
    • use a freed object
    • The same block of memory is freed twice
  • In view of the above problems, it is recommended to use smart pointers in use.
  • code

    void test()
    {
        string s;
        // string *ps;
        // *ps = "233"; // 这种方法需要首先对指针进行赋值,否则会报错
    
        string *p1 = new string;
        *p1 = "test";
        cout << *p1 << endl;
        delete p1; // 必须手动释放内存
    
        int *p2 = new int(42);
        delete p2;
    
        // 如果出现了内存不够导致无法分配内存的情况,可以使用nothrow,如果分配失败,则会返回空指针
        int *p3 = new (nothrow) int(50);
        cout << *p3 << endl;
    
        const string* p4 = new string("hello");
        // *p4 = "ssss"; // 因为是const对象,无法修改其值,会报错
        delete p4;
    }
    

shared_ptr combined with new

  • If the smart pointer is not initialized, it will be initialized to a null pointer, and a built-in pointer can be converted to a smart pointer by direct initialization . Note: Such initialization cannot be achieved by the method of hermit conversion

  • code

    void test()
    {
        // shared_ptr<int> p1 = new int(4); // 无法通过这样的方法实现隐式转换
        shared_ptr<int> p2( new int(42) ); // 可以通过直接初始化的方式实现智能指针的初始化
        cout << *p2 << endl;
    }
    

get

  • get returns a built-in pointer to the object managed by the smart pointer.
  • It is not recommended to use this property because it may mess up memory space management.
  • code

    void another(int *p)
    {
        shared_ptr<int> ret( p );
    }
    
    void test()
    {
        shared_ptr<int> p1( new int(5) );
        another(p1.get() );
        // p1所对应的内存空间会在another函数中被释放,下面的操作在运行的时候会出现错误
        //int num = *p1;
        //cout << num << endl;
    }
    

Customize the action when the smart pointer is released

  • The smart pointer can call the destructor by itself to release resources. We can also specify the deletion operation of this smart pointer object, and we need to pass in a pointer object, the type is the data type. Even if it is an exception, a custom function will be called to release resources
  • code

    void freed(int *p)
    {
        delete p;
        cout << "p is being deleted" << endl;
    }
    
    void test()
    {
        // 自定义析构的函数
        shared_ptr<int> p1( new int(5), freed );
        // throw out_of_range("2333"); // 即使是出现异常,也可以调用freed进行资源释放
    }
    

unique_ptr

  • The previous shared_ptr is a method of reference counting, allowing multiple variables to use the same block address, and unique_ptrcan only point to a given object, which can be directly initialized by using new
  • unique_ptr does not support copy and assignment
  • unique_ptrThe ownership of a pointer can be transferred from one to another through the release and reset methods unique_ptr.
  • code

    void test()
    {
        unique_ptr<int> p1(new int(4));
        cout << *p1 << endl;
        //不支持拷贝与赋值
        // unique_ptr<int> p2( p1 ); 
        // unique_ptr<int> p2 = p1;
        unique_ptr<int> p2( p1.release() ); // release:p1放弃对指针的控制权,将p1置为空,同时返回该指针
        cout << (p1 == NULL ? "p1 is NULL" : "p1 is not NULL") << endl;
        cout << *p2 << endl;
    
        p2.reset(); // 释放了p2所指的内存,同时将p2置为空
        cout << (p2 == NULL ? "p2 is NULL" : "p2 is not NULL") << endl;
    }
    

deleter

  • By default, unique_ptrboth shared_ptruse delete to release the object it refers to; at the same time, a deleter can also be unique_ptrpassed in, but the usage method shared_ptris different, he needs to pass in 2 type templates
  • code

    void freed(int *p)
    {
        delete p;
        cout << "p is being deleted" << endl;
    }
    
    void test()
    {
        // 可以使用decltype进行函数指针的声明,方便一些
        //unique_ptr<int, decltype(freed)*> p1( new int(4), freed );
        unique_ptr<int, void(*)(int*)> p1(new int(4), freed);
        cout << *p1 << endl;
    }
    

weak_ptr

  • Rarely used, not introduced here

dynamic array

  • The objects allocated by new, whether individually allocated or in an array, are initialized by default. You can add a pair of empty parentheses after the definition to implement value initialization.
  • It is legal to dynamically allocate an array of size 0, but the array cannot be dereferenced.
  • The way to release the array can be used delete [] p, if it is a single value, delete pyou can use it.
  • The standard library provides a unique_ptrversion that can manage arrays allocated by new. When the smart pointer is released, it will call delete [] pto release the array resources, but shared_ptrthere is no such operation. If it needs to manage the array, we need to customize the deleter

    void test()
    {
        int *p1 = new int[10]; //没有初始化
        int *p2 = new int[10](); // 初始化值为0
        int *p3 = new int[10]{1,2,3,4};
        cout << *p1 << ", " << *p2 << endl;
        for (int i = 0; i < 10; i++)
            cout << p3[i] << " ";
        cout << endl;
    
        int *p4 = new int[0](); // 初始化大小为0没有问题
        //cout << *p4 << endl; //在这里解引用会出现意想不到的结果
    
    
        delete[] p1;
        delete[] p2;
        delete[] p3;
        delete[] p4;
    
    
        cout << "unique_ptr\n";
        unique_ptr<int[]> p5(new int[10]{1,2,3,4,5,6});
        for (int i = 0; i < 10; i++)
            cout << p5[i] << " ";
        cout << endl;
    
        cout << "shared_ptr\n";
        shared_ptr<int> p6(new int[10]{8, 7, 6, 5, 4}, [](int *p){ 
            cout << "user defined delete func for shared_ptr" << endl;
            delete[] p; });
        for (int i = 0; i < 10; i++)
            cout << *(p6.get()+i) << " "; // 没有实现上面的下标引用访问的方式
        cout << endl;
    }
    

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325485973&siteId=291194637