C++中的动态内存分配

常见的程序崩溃的原因:

  1. 由assert()触发的;
  2. 操作内存时,越界了;
  3. 内存没有被初始化就拿去用了;
  4. 栈溢出了;
  5. 使用了野指针。
    总之,非法操作内存会对引起程序崩溃。

C中动态内存管理方式:

使用malloc/calloc/realloc/free进行动态内存管理。
malloc、calloc、realloc的相同点与不同点:
相同点:

  1. 都是在堆上开辟空间的。
  2. 都是通过free来释放空间的。
  3. 返回值:成功都是void*,失败都是NULL。

不同点:(体现在每个函数的功能和参数列表不同)

  1. malloc只负责把空间开辟出来。malloc(字节数)
  2. calloc(单个元素所占字节数的大小,需要的元素个数)
  3. realloc对空间进行扩增和缩减,
    realloc(地址,新开辟空间的大小)
    // 如果新的大小大于原内存大小,则新分配不会被初始化;
    // 如果新的大小小于原内存大小,则可能会导致部分数据丢失

面试题:什么是内存泄露?如何检测一个系统是否存在内存泄露?

常见的内存泄露:

void MemoryLeaks()
{
    //1.内存申请了,忘了释放
    int *pstr = (int*)malloc(sizeof(int));
    assert(pstr);

    //2.逻辑不清,以为自己释放了,实际造成了内存泄露
    int *p1 = (int*)malloc(sizeof(int));
    int *p2 = (int*)malloc(sizeof(int));
    p1 = p2;//p1指向p2的空间,p1原来指向的空间就找不到了,此时p1和p2指向同一块空间
    free(p1);//p1将p2指向的空间释放了
    free(p2);//p2又来释放,导致同一块空间释放多次

    //3.溢出,将堆破坏了
    char *pstr = (char*)malloc(5);//只开辟了5个空间
    strcpy(pstr, "hello word!!!");//strcpy不会进行类型检测
    free(pstr);

    //4.释放时传入的地址和申请时的地址不相同
    int *p = (int*)malloc(sizeof(int));
    p++;
    free(p);

}

C++内存管理方式:

C语言内存管理方式在C++中可以继续使用,但尽量使用自己的内存管理方式:C++中通过new和delete运算符进行动态内存管理

void TestNewDelete()
{
    int* p1 = new int;//申请单个空间(4个字节)
    //delete p1;

    int* p2 = new int(10);//申请单个空间(4个字节)并将其初始化为10
    //delete p2;

    int* p3 = new int[10];//申请了10个一段连续的空间(40个字节)
    //delete[] p3;

    delete p1;
    delete p2;
    delete[] p3;
}
int main()
{
    TestNewDelete();
    return 0;
}

C语言动态申请内存空间须:

  1. 申请后要对其进行判空。
  2. 要传入想要申请的字节数。
  3. 若要接受开辟的这段空间,必须对其进行类型转化。

C++不需要。

注意:
1. new和delete是运算符,而不是函数;但malloc / calloc / realloc / free都是函数。
2. new和delete、new和delete[]一定要匹配使用!!!否则会出现内存泄露甚至程序发生崩溃。

malloc/free和new/delete比较

  1. 测试malloc和free、new和delete、new和delete[]都没有匹配起来时:
void Test()
{
    int *p1 = (int*)malloc(sizeof(int));
    int *p2 = (int*)malloc(sizeof(int));

    int *p3 = new int;
    int *p4 = new int;

    int *p5 = new int[10];
    int *p6 = new int[10];

    delete p1;
    delete[] p2;

    free(p3);
    delete[] p4;

    free(p5);
    delete p6;
}
int main()
{
    Test();
    return 0;
}

上述代码能通过编译,也能正常运行,不存在内存泄露

构造Test类,再来测试以下代码:

class Test
{
public:
    Test()
    {
        cout << "Test:" << this << endl;
    }

    /*~Test()
    {
        cout << "~Test:" << this << endl;
    }*/
};
void main()
{
    Test *p1 = (Test*)malloc(sizeof(Test));
    Test *p2 = (Test*)malloc(sizeof(Test));
    delete p1;//此处会打印出析构函数体的内容,即此处调用了析构函数
    delete[] p2;//程序发生崩溃,如果将析构函数屏蔽掉,则不会发生崩溃

    Test *p3 = new Test;//此处会打印出构造函数体的内容,即此处调用了构造函数
    Test *p4 = new Test;//此处会打印出构造函数体的内容,即此处调用了构造函数
    free(p3);
    delete[] p4;//程序发生崩溃

    Test *p5 = new Test[10];//此处调用了10次构造函数
    Test *p6 = new Test[10];//此处调用了10次构造函数
    free(p5);//程序发生崩溃
    delete p6;

}

猜你喜欢

转载自blog.csdn.net/bit666888/article/details/81161118