C++的内存管理

C++的内存管理

C++的内存堆空间的申请和释放完全靠自己管理 程序运行时所需的内存空间分为固定部分和可变部分 固定部分:一般为代码区:存放二进制代码 数据区:存放全局变量和静态变量,常量

可变部分:堆区:运行方法的形参,局部变量,返回值,以及递归栈所需的空间,系统自动分配和回收 栈区:动态开辟的空间,存放“new”出来的对象在堆区中的真实数据,需要手动回收

栈区stack:由编译器自动分配释放,存放函数的参数值、局部变量的值灯,其操作方式类似于数据结构中的栈 堆区heap:由程序员手动分配释放,存放程序运行时创建的对象,其操作方式类似于数据结构中的堆 如果程序员不释放,程序结束时会自动释放,可能导致内存泄漏 未初始化数据区:存放未初始化的全局变量和静态变量 初始化数据区:存放已初始化的全局变量和静态变量

C 风格内存管理

malloc 函数(memory allocation)

用于在堆上分配指定字节数的内存。其原型如下:

#include <cstdlib>
void* malloc(size_t size);

参数:size - 要分配的内存字节数。 返回值:指向分配内存的指针,如果分配失败则返回 nullptr

free 函数(memory deallocation)

用于释放由 malloc 分配的内存。其原型如下:

#include <cstdlib>
void free(void* ptr);

参数:ptr - 指向要释放的内存的指针。 无返回值

桑婆

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

int main()
{
    int* p = (int*)malloc(sizeof(int));
    if(p == nullptr){
        cout << "Memory allocation failed" << endl;
        return 1;
    }
    *p = 666;
    cout << "The value of *p is " << *p << endl;
    free(p);
    return 0;
}

Warning 类型转换:malloc 返回 void*,需要显式转换为所需类型的指针。 初始化:malloc 分配的内存未初始化,内容不确定。 释放对应性:由 malloc 分配的内存必须使用 free 释放,避免使用 delete。

C++ 风格内存管理

new 运算符(object creation)

用于在堆上分配对象,并调用其构造函数。

Type* ptr = new Type(parameters);

可以new对象 桑婆

#include <iostream>
using namespace std;

class Sample{
    public:
        int value;
        Sample(int x):value(x){}
};

int main()
{
    Sample* ptr = new Sample(10);
    cout << ptr->value << endl;
    return 0;
}

可以new数组:

#include <iostream>
using namespace std;

int main()
{
    int* ptr = new int[10];
    for(int i=0;i<10;i++){
        ptr[i] = i;
    }
    for(int i=0;i<10;i++){
        cout << ptr[i] << " ";
    }
    return 0;
}

delete 运算符(object destruction)

用于销毁对象,并释放其内存。 删除单个对象

delete ptr;

释放数组

delete[] ptr;

区别于 malloc 和 free

类型安全:new 返回正确类型的指针,免去了强制类型转换。 构造/析构:new 和 delete 自动调用构造函数和析构函数。 异常处理:在分配失败时,new 默认抛出 std::bad_alloc 异常,而 malloc 返回 nullptr。

可以用nothrow来避免new的异常:

In C++, std::nothrow is a constant of type std::nothrow_t, which is an empty class type used to differentiate between throwing and non-throwing allocation functions. When using std::nothrow, the new operator does not throw an exception if memory allocation fails. Instead, it returns a null pointer, allowing the programmer to handle the failure explicitly.

alt text

高级内存管理

使用 realloc 进行内存重分配

#include <cstdlib>
void* realloc(void* ptr, size_t size);

ptr:指向之前分配的内存块。 new_size:新的内存大小(以字节为单位)。 返回值:指向重新分配后的内存块的新指针。如果重新分配失败,返回 nullptr,原内存块保持不变。

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

int main()
{
    int* ptr = (int*) malloc (5 * sizeof(int));
    for(int i = 0; i < 5; i++)
    {
        ptr[i] = i;
    }
    cout << "Before realloc: ";
    for(int i = 0; i < 5; i++){
        cout << ptr[i] << " ";
    }
    int* ptr2 = (int*) realloc(ptr, 10 * sizeof(int));
    for(int i=5;i < 10;i++)
    {
        ptr2[i] = i;
    }
    cout << "After realloc: ";
    for(int i = 0; i < 10; i++){
        cout << ptr2[i] << " ";
    }
    return 0;
}

output

Before realloc: 0 1 2 3 4 After realloc: 0 1 2 3 4 5 6 7 8 9

实现一个动态数组(使用realloc)

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

class DynamicalArray {
    public:

    int* ptr;
    int size;
    DynamicalArray(int initial_size=1):size(initial_size), ptr((int*)malloc(size*sizeof(int))){cout<<"Create"<<endl;}

    ~DynamicalArray(){free(ptr);cout<<"Delete"<<endl;}

    void resize(int new_size) {
        int* new_ptr = (int*)realloc(ptr, new_size*sizeof(int));
        if(new_ptr) {
            ptr = new_ptr;
            size = new_size;
            cout<<"Resize to "<<size<<endl;
        }
    }

    int getSize() const {return size;}

    void show(){
        for(int i=0;i<size;i++){
            cout<<ptr[i]<<" ";
        }
        cout<<endl;
    }
};
int main()
{
    DynamicalArray arr(5);
    for(int i=0;i<5;i++){
        arr.ptr[i] = i;
    }
    arr.show();
    arr.resize(10);
    for(int i=5;i<10;i++){
        arr.ptr[i] = i;
    }
    arr.show();
    return 0;
}



Enjoy Reading This Article?

Here are some more articles you might like to read next: