解析c++动态内存管理

在说今天的主题前我们先来回顾 C语言中的动态内存管理。

在C语言,使用的是malloc/calloc/realloc/free在堆上动态的开辟或修改一块连续的空间。我们先来回顾一下这些函数的区别。

(1)malloc:void *malloc( size_t size );

malloc函数在使用时,只需要传递一个参数size,那就是将要分配内存的大小,一般需用sizeof(type)*num手动计算。有时malloc所申请的空间可能会比实际所申请的空间要大,要用来存放维护信息等。

(2)calloc: void *calloc( size_t num, size_t size );

calloc与malloc都是在堆上申请一块连续的空间,不过calloc申请的空间都已初始化,并且需要传递两个参数,所以,calloc是在堆上申请num个大小为size的连续空间。

(3)realloc: void *realloc( void *memblock, size_tsize);

memblock函数有两个参数,memblock是所要修改空间的地址,size是重新申请的地址长度。

如果memblock不为NULL,则会对已分配好的内存进行修改,如果所要修改的内存过大,realloc会重新申请一块空间,并将内容完全复制过来,返回新空间的首地址,并将原有空间进行销毁。

如果memblock为NULL,则分配行为与malloc相同。

了解了上述内容,我们来看看关于c++的动态内存管理是怎么回事呢?

c++是通过new和delete操作符实现的。

new/delete动态管理对象。
new[]/delete[]动态管理对象数组。

特别注意new和delete它不是函数,而是操作符!

那么接下来我们来看看具体的实例吧

void Test ()
{
int* p4 = new int; // 动态分配4个字节(1个 int)的空间单个数据
int* p5 = new int(3); // 动态分配4个字节(1个 int)的空间并初始化为3
int* p6 = new int[3]; // 动态分配12个字节(3个 int)的空间
delete p4 ;
delete p5 ;
delete[] p6 ;
}

特别注意:new/delete,new[]/delete[]一定要匹配使用!!!

接着我们先来看一段代码


#include <iostream>
using namespace std;

class p1
{
public:
    p1(int a=0)
    :_a(a)
    {
        cout << "p1(int a)" << endl;
    }
    ~p1()
    {
        cout << "~p1()" << endl;
    }
    void display()
    {
        cout << _a << endl;
    }
private:
    int _a;
};

int main()
{
    p1* p = new p1(10);//创建类
    p->display();
     delete p;

    return 0;
}

代码运行成功后的结果如图所示:

这里写图片描述

这就说明了new在创建一个类时,会默认调用构造函数使类初始化。
而我们的delete是先调用析构函数,然后在进行释放。

在动态内存管理中
new做了两件事:
1.调用operator new分配空间。
2.调用构造函数初始化对象。

delete也做了两件事:
1.调用析构函数清理对象
2.调用operator delete释放空间

new[N]做了两件事:
1.调用operator new分配空间。
2.调用N次构造函数分别初始化每个对象。

delete[]也做了两件事:
1.调用N次析构函数清理对象。
2.调用operator delete释放空间。

总结:
1.operator new/operator delete ,operator new[]/operator delete[] 和 malloc/free用法一样。
2.他们只负责分配空间/释放空间,不会调用对象构造函数/析构函数来初始化/清理对象。
3.实际operator new和operator delete只是malloc和free的一层封装。

知道了c++的动态内存的基本实现方法,我们来看看malloc/free与new/delete的有什么区别与联系?

(1). 它们都是动态管理内存的接口。
(2). malloc/free是C/C++标准库的函数,new/delete是C++操作符。
(3). malloc/free只是动态分配内存空间/释放空间。new/delete除了分配空间还会调构造函数和析构函数进初始化与清理(清理成员)。
(4). malloc/free需要手动计算类型并且返回值是void*,new/delete可以自己计算类型的大小,并返回对应类型的指针。
(5).malloc失败会返回0,new失败会抛出异常。

接下来我们来看看定位new表达式

定位new表达式是在已分配的原始内存空间中调用构造函数初始化一个对象,用法如下
new (place_address) type
new (place_address) type(initializer-list)
place_address必须是一个指针,initializer-list是类型的初始化列表。

接着我们来看它的具体实现吧:

#include <iostream>
#include<cstdlib>
using namespace std;
class AA
{
public:
    AA()


    {
        cout << "AA()" << endl;
    }
    ~AA()
    {
        cout << "~AA()" << endl;
    }
    void display()
    {
        cout << _a << endl;
    }
private:
    int _a;
};
int main()
{
    AA* p1 = new AA;
    AA* p2 = (AA*)malloc(sizeof(AA));//开辟空间
    new(p2)AA;//已分配的原始内存空间中调用构造函数初始化一个对象
    p2->display();
    delete p1;
    p2->~AA();
    //析构函数的显式调用,构造函数不能显示调用,一般不建议使用显示调用
    free(p2); 
}

代码运行成功后的结果是:

这里写图片描述

由_a的输出结果是0我们可以知道定位new表达式是在已分配的原始内存空间中调用构造函数初始化一个对象。

接着我们来通过定位new表达式来模拟实现new[]和delete[]

#include <iostream>
#include<cstdlib>
using namespace std;
class AA
{
public:
    AA()
        :_a(0)
    {
        cout << "AA()" << endl;
    }
    ~AA()
    {
        cout << "~AA()" << endl;
    }
    void display()
    {
        cout << _a << endl;
    }
private:
    int _a;
};

#define NEW_ARRAY(ptr,type,n)\
do                      \
{                       \
    ptr = (type*)operator new(sizeof(type)*n + 4); \
    *(int*)ptr = n;              \
    ptr = (type*)((char*)ptr + 4);   \
for (size_t i = 0; i < n; ++i)\
{                             \
    new(ptr + i)type;         \
}                                \
} while (false);


#define DELETE_ARRAY(PTR,TYPE)  \
do{                             \
int N = *((int*)PTR - 1);       \
for (int i = 0; i < N; ++i)     \
PTR[i].~TYPE();                 \
PTR =(TYPE*)((char*)PTR - 4);   \
operator delete(PTR);           \
}while (false);

int main()
{
    AA*p2;
    NEW_ARRAY(p2, AA, 10);
    DELETE_ARRAY(p2, AA);
    system("pause");
    return 0;
}

代码运行成功后的结果如图:

这里写图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值