【C++】内存管理

💗个人主页💗
⭐个人专栏——C++学习
💫点击关注🤩一起学习C语言💯💫

目录

1. C/C++内存分布

2. C语言中动态内存管理方式

3. C++内存管理方式

 3.1 new/delete操作内置类型

3.2 new和delete操作自定义类型

4. operator new与operator delete函数


1. C/C++内存分布

C/C++程序的内存分布主要分为以下几个部分:

  1. 栈(Stack):栈是用来存储局部变量、函数参数等的内存区域。每当一个函数被调用时,都会分配一块栈帧来存储函数的局部变量和参数。栈是按照"先进后出"的原则进行管理,函数返回后,其所占用的栈帧会被释放。

  2. 堆(Heap):堆是用来动态分配内存的区域。在C/C++中,使用new/delete或malloc/free来进行堆内存的动态分配与释放。堆是按照"先进先出"的原则进行管理,需要手动释放分配的内存。

  3. 全局/静态存储区(Global/Static Storage):全局变量和静态变量都存储在这个区域中。全局变量在程序运行期间一直存在,静态变量的生命周期是整个程序运行期间。

  4. 常量存储区(Constant Storage):存储常量数据,例如字符串常量。这个区域的数据在程序运行期间不能被修改。

  5. 代码区(Code/Text):存储程序的机器指令。代码区是只读的,程序在运行时不能修改代码区的内容。

2. C语言中动态内存管理方式

在C语言中,动态内存管理主要通过以下几个函数来实现:

  1. malloc():用于分配指定大小的字节内存块。它接受一个参数,即所需内存的字节数,并返回一个指向分配内存的指针。

  2. calloc():用于分配指定数量和大小的连续内存块,并将每个字节都初始化为零。它接受两个参数,即所需内存块的数量和每个内存块的字节数,并返回一个指向分配内存的指针。

  3. realloc():用于重新分配已分配内存块的大小。它接受两个参数,即指向要重新分配大小的内存块的指针和新的内存块大小,并返回一个指向重新分配内存的指针。

  4. free():用于释放之前通过malloc()或calloc()分配的内存块。它接受一个参数,即要释放的内存块的指针。

#include <stdio.h>
#include <stdlib.h>

int main() {
    int* numbers;
    
    // 分配存储5个整数的内存块
    numbers = (int*)malloc(5 * sizeof(int));
    if (numbers == NULL) {
        printf("内存分配失败\n");
        return 1;
    }
    
    // 向每个元素赋值
    for (int i = 0; i < 5; i++) {
        numbers[i] = i + 1;
    }
    
    // 打印每个元素的值
    for (int i = 0; i < 5; i++) {
        printf("%d ", numbers[i]);
    }
    printf("\n");
    
    // 重新分配内存块的大小为10个整数
    numbers = (int*)realloc(numbers, 10 * sizeof(int));
    if (numbers == NULL) {
        printf("内存重新分配失败\n");
        return 1;
    }
    
    // 向新增的元素赋值
    for (int i = 5; i < 10; i++) {
        numbers[i] = i + 1;
    }
    
    // 打印每个元素的值
    for (int i = 0; i < 10; i++) {
        printf("%d ", numbers[i]);
    }
    printf("\n");
    
    // 释放内存块
    free(numbers);
    
    return 0;
}

3. C++内存管理方式

C语言内存管理方式在C++中可以继续使用,但有些地方就无能为力,而且使用起来比较麻烦,因 此C++又提出了自己的内存管理方式:通过new和delete操作符进行动态内存管理。

  1. new/delete运算符:new运算符用于动态分配单个对象的内存,并返回指向该对象的指针,而delete运算符用于释放通过new分配的内存。相较于malloc/free函数,new和delete可以自动调用对象的构造函数和析构函数。

  2. new[]/delete[]运算符:new[]运算符用于动态分配对象数组的内存,并返回指向该数组的指针,而delete[]运算符用于释放通过new[]分配的内存。相较于malloc/free函数,new[]和delete[]可以自动调用每个对象的构造函数和析构函数。

 3.1 new/delete操作内置类型

1. new操作符:使用new操作符可以动态分配内置类型的内存空间,并返回指向该内存空间的指针。

int* p = new int; // 动态分配一个int类型的内存空间
float* q = new float; // 动态分配一个float类型的内存空间

2. delete操作符:使用delete操作符可以释放通过new操作符分配的内存空间,同时调用内置类型的析构函数进行资源的清理。

delete p; // 释放之前分配的int类型的内存空间
delete q; // 释放之前分配的float类型的内存空间

需要注意的是,对于内置类型,因为它们没有构造函数和析构函数,所以delete操作符只会释放内存空间,并不会进行其他操作。

而且,使用delete操作符释放的内存空间必须是通过new操作符进行分配的,否则可能导致未定义的行为。另外,动态分配的内置类型的内存空间一旦不再需要,应当及时释放,以避免内存泄漏和资源的浪费。

void Test()
{
  // 动态申请一个int类型的空间
  int* ptr4 = new int;
  
  // 动态申请一个int类型的空间并初始化为10
  int* ptr5 = new int(10);
  
  // 动态申请10个int类型的空间
  int* ptr6 = new int[3];
  delete ptr4;
  delete ptr5;
  delete[] ptr6;
}

3.2 new和delete操作自定义类型

class MyClass 
{
public:
    int* data;

    MyClass() 
    {
        data = new int[5]; // 动态分配一个包含5个int元素的数组
        cout << "Constructor called" << endl;
    }

    ~MyClass() 
    {
        delete[] data; // 释放之前分配的数组内存空间
        cout << "Destructor called" << endl;
    }
};

int main() 
{
    MyClass* obj = new MyClass(); // 动态分配一个MyClass对象的内存空间,并进行初始化

    // 使用动态分配的内存空间
    for (int i = 0; i < 5; i++) 
    {
        obj->data[i] = i;
        cout << obj->data[i] << " ";
    }
    cout << endl;

    delete obj; // 释放之前分配的MyClass对象的内存空间,并调用析构函数

    return 0;
}

4. operator new与operator delete函数

operator new和operator delete是C++中的全局函数,用于自定义类对象的动态内存管理。new在底层调用operator new全局函数来申请空间,delete在底层通过 operator delete全局函数来释放空间。

 注意:operator new和operator delete不是对new和delete的重载,这是俩库函数

operator new函数用于分配内存空间:

void* operator new (std::size_t size);

它接受一个参数size,表示要分配的内存空间的大小,返回一个void指针,指向已分配的内存空间的起始地址。

operator delete函数用于释放内存空间:

void operator delete (void* ptr);

它接受一个参数ptr,表示要释放的内存空间的起始地址,无返回值。

这两个函数可以被重载,用于自定义内存分配和释放的行为。

class MyClass 
{
public:
    int data;

    MyClass(int d) : data(d) 
    {
        std::cout << "Constructor called" << std::endl;
    }

    ~MyClass() 
    {
        std::cout << "Destructor called" << std::endl;
    }

    static void* operator new (size_t size) 
    {
        std::cout << "Custom new operator called" << std::endl;
        void* ptr = std::malloc(size); // 使用malloc来分配内存空间
        if (!ptr) 
        {
            throw std::bad_alloc(); // 内存分配失败,抛出异常
        }
        return ptr;
    }

    static void operator delete (void* ptr) 
    {
        std::cout << "Custom delete operator called" << std::endl;
        std::free(ptr); // 使用free来释放内存空间
    }
};

int main() 
{
    MyClass* obj = new MyClass(10);
    delete obj;

    return 0;
}

  

相关推荐

  1. C/C++——内存管理

    2024-02-20 23:36:01       65 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-02-20 23:36:01       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-02-20 23:36:01       106 阅读
  3. 在Django里面运行非项目文件

    2024-02-20 23:36:01       87 阅读
  4. Python语言-面向对象

    2024-02-20 23:36:01       96 阅读

热门阅读

  1. 什么是机器学习

    2024-02-20 23:36:01       57 阅读
  2. PS的常用快捷方式有哪些?

    2024-02-20 23:36:01       54 阅读
  3. GET变量与POST变量

    2024-02-20 23:36:01       57 阅读
  4. 软考笔记--信息系统开发方法(上)

    2024-02-20 23:36:01       49 阅读
  5. CES 的Agent插件状态显示“故障”该如何处理?

    2024-02-20 23:36:01       55 阅读
  6. 游戏分组/王者荣耀

    2024-02-20 23:36:01       44 阅读
  7. 关于游戏开发的那些工具

    2024-02-20 23:36:01       49 阅读