C/C++ memory management (including the use of new and delete in C++)


img

C/C++ memory management (including the use of new and delete in C++)

1. C/C++ memory distribution

Let’s first look at the following piece of code and related questions.

int globalVar = 1;
static int staticGlobalVar = 1;

int main() {
     
     
    static int staticVar = 1;
    int localVar = 1;
    int num1[10] = {
     
     1, 2, 3, 4};
    char char2[] = "abcd";
    const char *pChar3 = "abcd";
    int *ptr1 = (int *) malloc(sizeof(int) * 4);
    int *ptr2 = (int *) calloc(4, sizeof(int));
    int *ptr3 = (int *) realloc(ptr2, sizeof(int) * 4);
    free(ptr1);
    free(ptr3);
    return 0;
}
//1. 选择题:
// 选项: A.栈 B.堆 C.数据段(静态区) D.代码段(常量区)
// globalVar在哪里?____  staticGlobalVar在哪里?____
// staticVar在哪里?____  localVar在哪里?____
// num1 在哪里?____
//
// char2在哪里?____  *char2在哪里?___
// pChar3在哪里?____   *pChar3在哪里?____
// ptr1在哪里?____ *ptr1在哪里?____
//2. 填空题:
// sizeof(num1) = ____; 
//sizeof(char2) = ____;  strlen(char2) = ____;
// sizeof(pChar3) = ____;   strlen(pChar3) = ____;
// sizeof(ptr1) = ____;
//3. sizeof 和 strlen 区别?
//

  • Description:
    1. stack is also called stack –non-static local variables/function parameters/return values etc. The stack grows downward.
    2. memory mapped segment is an efficient I/O mapping method for loading a shared dynamic memory library. Users can use the system interface to create shared shared memory for inter-process communication. (LinuxIf you haven’t learned this in the course, you just need to understand it now)
    3. heap is used for dynamic memory allocation when the program is running, and the heap can grow.
    4. data segmentStore global data and static data.
    5. code snippetExecutable code/read-only constants.

So there is an answer to the multiple choice question 1.

Then the answer to 2. Fill in the blank question is: Have you learned it before? Haha.

Part 3.sizeof Japanese strlen Different?

Answer: strlen ends when \0 is encountered, strlen calculates the string length, sizeofCalculate the size of the variable.


2. Dynamic memory management method in C language: malloc/calloc/realloc/free

malloc, calloc and realloc are three functions used for dynamic memory allocation in C language. They have some differences, mainly reflected in their Function and usage.

  1. malloc (Memory Allocation, memory allocation):

    • mallocIt is the abbreviation of "memory allocation" and is used to allocate a memory block of a specified size.
    • It only allocates memory without initializing it, so the allocated memory may contain arbitrary values.
    void* malloc(size_t size);
    
  2. calloc (Contiguous Allocation, continuous allocation):

    • calloc is also a function used to allocate memory, but unlike malloc, the memory block allocated by calloc will be Initialized to zero.
    • callocAccepts two parameters, the required number of elements and the size of each element.
    void* calloc(size_t num_elements, size_t element_size);
    
  3. realloc (Re-allocation, reallocation):

    • realloc is used toreallocate the size of allocated memory, which can be used to expand or reduce the size of the memory block.
    • If the address of the original memory block is not empty,realloc will try to modify the size of the memory block at the original address (if the new memory size is larger than the original space, you still need to re- allocate memory), if the original address is empty, the behavior is similar to malloc.
    void* realloc(void* ptr, size_t new_size);
    

Summarize:

  • mallocOnly a memory block of the specified size is allocated without initialization.
  • callocAllocates a memory block of the specified number and size and initializes all bits of the memory block to zero.
  • reallocReallocates the size of a memory block, which can be used to expand or shrink the size of allocated memory.
int main() {
     
     
    int *p1 = (int *) malloc(sizeof(int));
    free(p1);
// 1.malloc/calloc/realloc的区别是什么?
    int *p2 = (int *) calloc(4, sizeof(int));
    int *p3 = (int *) realloc(p2, sizeof(int) * 10);
// 这里需要free(p2)吗? --- 看情况
    free(p3);
    return 0;
}

3. C++ dynamic memory management

The C language memory management method can continue to be used in C++, but there are some places where it cannot be used (such as initializing objects), and it is more troublesome to use. Therefore,C++ has proposed its own Memory management method: dynamic memory management through new and delete operators.

3.1. New/delete operation built-in types

int main() {
     
     
    // 动态申请一个int类型的空间
    int *ptr4 = new int;

    // 动态申请一个int类型的空间并初始化为10
    int *ptr5 = new int(10);

    cout << *ptr5 << endl;
    // 动态申请10个int类型的空间
    int *ptr6 = new int[3];
    // 动态申请10个int类型的空间并初始化前3个
    int *ptr7 = new int[3]{
     
     1, 2, 3};
    cout << ptr7[0] << ptr7[1] << ptr7[2] << ptr7[3];
    
    delete ptr4;
    delete ptr5;
    delete[] ptr6;
    delete[] ptr7;
}
  • initialization format
    • Single element space:new 类型 (初始化值)
    • Continuous space:new 类型 [元素个数] {从前往后元素初始化值,其余元素初始化为0}
  • Note: To apply for and release the space of a single element, use the new and delete operators to apply for and release For continuous spaces, use new[] and delete[]. Note: is matched using .

3.2. New/delete operation custom type

class Date {
     
     
public:
    Date() : _year(1), _month(1), _day(1) {
     
     
        cout << "Date()" << endl;
    }

    Date(int year, int month, int day) : _year(1), _month(1), _day(1) {
     
     
        _year = year;
        _month = month;
        _day = day;
        cout << "Date()" << endl;
    }

    ~Date() {
     
     
        cout << "~Date()" << endl;
    }

private:
    int _year;
    int _month;
    int _day;
};


int main() {
     
     
    Date *ptr1 = new Date();
    Date *ptr2 = new Date(2, 2, 2);

    Date *ptr3 = new Date[10]{
     
     {
     
     1, 2, 2}};

    free(ptr1);
    delete ptr2;
    delete[] ptr3;
    return 0;
}

  • initialization format
    • Single element space:new 类型 (初始化值)
    • Continuous space:new 类型 [元素个数] {从前往后元素初始化值使用{}代表每一个元素的值,其余元素初始化为0}
  • new/deleteThe biggest difference between and malloc/free is that new/delete for [custom type] in addition to opening space, the constructor and destructor will also be called

4. operator new and operator delete functions

new and delete are the operators for users to apply for and release dynamic memory. operator new and operator delete are provided by the system. Global functions, new call global functions at the bottom layer to apply for space, a> global function. through the bottom layerFree space at the operator newdeleteoperator delete

  • operator new: This function actually applies for space through malloc, and returns directly when malloc successfully applies for space; fails to apply for space, and attempts to implement insufficient space countermeasures , if the user has set the countermeasure, continue to apply, otherwise an exception will be thrown.
  • operator delete is finally released throughfree.
class Date {
     
     
public:
    Date() : _year(1), _month(1), _day(1) {
     
     
        cout << "Date()" << endl;
    }

    Date(int year, int month, int day) : _year(1), _month(1), _day(1) {
     
     
        _year = year;
        _month = month;
        _day = day;
        cout << "Date()" << endl;
    }

    ~Date() {
     
     
        cout << "~Date()" << endl;
    }

private:
    int _year;
    int _month;
    int _day;
};


int main() {
     
     
    //operator new -- 不调用构造函数 和 malloc 基本一样
    Date *ptr6 = (Date *) operator new(sizeof(Date));

    delete new(ptr6) Date;
    ptr6 = nullptr;
    return 0;
}

5. Implementation principles of new and delete

5.1. Built-in types

If you are applying for a built-in type of space, new and malloc, delete and freeBasically similar, the difference is: new/delete applies for and releases the space of a single element, new[] and delete[]Apply for continuous space, and newwill throw an exceptionwhen the space application fails, malloc will return NULL.

5.2. Custom type

  • newprinciple

    1. Calloperator newfunction to apply for space
    2. Execute the constructor on the requested space to complete the construction of the object
  • deleteprinciple

    1. Execute the destructor on the space to complete the cleanup of resources in the object
    2. Calloperator deletefunction to release the object’s space

  • new T[N]principle

    1. callsoperator new[] function, and actually calls function in operator new[] to complete Application for object spaceoperator newN

    2. Execute the constructorN times on the requested space

  • delete[]principle

    1. Execute the destructor on the released object spaceN times to complete the cleanup of resources in N objects

    2. Calloperator delete[] to release space, actually call in operator delete[] to release spaceoperator delete

Here we need to pay attention to a phenomenon: For built-in types, when new T[N], the memory space opened is often larger than N*sizeof(T), which may be more Out4 bytes.

Originally the space size opened hereptr2 should be12*10 = 120, but here it shows124, where 4 bytes are used to store the number of open consecutiveDate objects.

class Date {
      
      
public:
    Date() : _year(1), _month(1), _day(1) {
      
      
        cout << "Date()" << endl;
    }

    Date(int year, int month, int day) : _year(1), _month(1), _day(1) {
      
      
        _year = year;
        _month = month;
        _day = day;
        cout << "Date()" << endl;
    }

    ~Date() {
      
      
        cout << "~Date()" << endl;
    }

private:
    int _year;
    int _month;
    int _day;
};


int main() {
      
      
    Date* ptr1 = new Date;
    delete ptr1;

    Date* ptr2 = new Date[10];
    delete[] ptr2;
    return 0;
}

But if it is a built-in typenew T[N], no additional space is needed to store the number.

Originally the space opened here should be, and it is displayed here, that is, there is no space to store the number. ptr3size4*10 = 4040

class Date {
      
      
public:
    Date() : _year(1), _month(1), _day(1) {
      
      
        cout << "Date()" << endl;
    }

    Date(int year, int month, int day) : _year(1), _month(1), _day(1) {
      
      
        _year = year;
        _month = month;
        _day = day;
        cout << "Date()" << endl;
    }

    ~Date() {
      
      
        cout << "~Date()" << endl;
    }

private:
    int _year;
    int _month;
    int _day;
};


int main() {
      
      
    Date* ptr1 = new Date;
    delete ptr1;

    Date* ptr2 = new Date[10];
    delete[] ptr2;
  
  	int* ptr3 = new int[10];
		delete[] ptr3;
    return 0;
}

reason: The extra 4 bytes are used to record the number of continuous spaces of T size opened, so as to facilitate < a i=3> perform destruction and release space. delete []

If you do not write a destructor here (the default member variables do not open up space, if you open up space, you must call the destructor to release the space, otherwise memory leaks will occur), then no error will be reported, because the member variables are all built-in types There is no open space, no need to call the destructor, and there is no need to add 4 the number of bytes in front, that is, the custom type new T[N] can be directly a>delete, the same is true for built-in types.

class Date {
      
      
public:
    Date() : _year(1), _month(1), _day(1) {
      
      
        cout << "Date()" << endl;
    }

    Date(int year, int month, int day) : _year(1), _month(1), _day(1) {
      
      
//        _a = new int[10];
        _year = year;
        _month = month;
        _day = day;
        cout << "Date()" << endl;
    }

//    ~Date() {
      
      
//        cout << "~Date()" << endl;
//    }

private:
//    int* _a;
    int _year;
    int _month;
    int _day;
};


int main() {
      
      
    Date *ptr1 = new Date;
    delete ptr1;

    Date *ptr2 = new Date[10];
    // 这里如果不写析构函数(默认成员变量没有开辟空间,如果开辟了空间,必须调用析构函数释放空间,不然会内存泄露)的话就不报错
    // 因为成员变量都是内置类型没有开空间,不需要调用析构函数,也就不需要在前面添加4字节存个数
    delete ptr2;
    return 0;
}

Originally the size of the space allocated hereptr2 should be12*10 = 120, and it is displayed here120, that is, there is no allocated space. Number of objects.


6. Position new expression (placement-new)

The positioning new expression is to call the constructor to initialize an object in the allocated original memory space.

  • Used case:new (place_address) typeor personnew (place_address) type(initializer-list)
    • place_address must be a pointer, initializer-list is the initialization list of the type
  • Usage scene
    • PositioningnewExpressions generally match in practicememory poolUse. Because the memory allocated by the memory pool is not initialized, if it is a custom type object, you need to use the definition expression of new to explicitly call the constructor for initialization.
class Date {
     
     
public:
    Date() : _year(1), _month(1), _day(1) {
     
     
        cout << "Date()" << endl;
    }

    Date(int year, int month, int day) : _year(1), _month(1), _day(1) {
     
     
        _year = year;
        _month = month;
        _day = day;
        cout << "Date()" << endl;
    }

    ~Date() {
     
     
        cout << "~Date()" << endl;
    }

private:
    int _year;
    int _month;
    int _day;
};


int main() {
     
     
    Date *p = (Date *) operator new(sizeof(Date));
    // 不能显式调用构造函数
    // p->Date();
    // 定位new可以显式调用构造函数
    new(p)Date(1, 1, 1);
    p->~Date();

    return 0;
}

OKOK, that’s it for C/C++ memory management. If you are also interested in Linux and C++, you can check out my homepage. Below is my github homepage, which records my learning code and solutions to some problems of leetcode. If you are interested, you can take a look.

Xpccccc’s github homepage

Guess you like

Origin blog.csdn.net/qq_44121078/article/details/134697667
Recommended