C++内存管理

本文介绍了C++中的内存划分,包括栈、堆、内存映射段、数据段和代码段。详细阐述了new和delete操作内置类型及自定义类型内存的方式,并讨论了operatornew和operatordelete的作用。此外,还提到了定位new表达式用于已分配空间的构造函数初始化,以及内存泄漏的概念和示例。
摘要由CSDN通过智能技术生成

一、内存划分

C++会把内存分成5块来管理:

  1. 栈:非静态的局部变量,函数的参数、返回值,函数栈帧的开辟都在栈上,栈是向下增长的,也就是说越在后面申请的非静态局部变量,地址越小;

  1. 堆:malloc/calloc/realloc/free以及new/delet这类动态申请的空间都在堆上开辟,堆是向上增上的;

  1. 内存映射段:(Linux笔记中的进程间通信会详细讲解);

  1. 数据段:也叫静态区,用来存放静态的和全局的数据;

  1. 代码段:也叫常量区,用来存放可执行的二进制代码以及常量。

二、new与delete

  1. 内置类型

int main()
{
    // new 后跟类型名可以在堆上申请该类型大小的空间
    // 并返回该空间的首地址
    // delet 后跟 new 的空间的首地址可以释放空间
    int* p1 = new int;
    cout << "p1未初始化,会是随机值" << endl << *p1 << endl << endl;
    delete p1;

    // 申请单个空间,在类型后+()可以初始化
    double* p2 = new double(2.2);
    cout << "p2初始化为2.2" << endl << *p2 << endl << endl;
    delete p2;

    // 申请一块连续的空间,需要在类型后+[],里面放需要申请的个数
    // 连续的空间在释放时 delete 后要跟[],里面不用放数据
    int* p3 = new int[5];
    cout << "p3的5个元素未初始化,为随机值" << endl;
    for (int i = 0; i < 5; ++i)
    {
        cout << p3[i] << " ";
    }
    cout << endl << endl;
    delete[] p3;

    // 申请连续的空间的初始化,需要在[]后+ {}
    // {} 里放初始化的数据
    int* p4 = new int[10]{ 1,2,3,4,5 };
    cout << "p4的5个元素初始化为1,2,3,4,5,剩下5个元素应为0" << endl;
    for (int i = 0; i < 10; ++i)
    {
        cout << p4[i] << " ";
    }
    cout << endl << endl;
    delete[] p4;

    return 0;
}

2.自定义类型

class Test
{
private:
    int _a;
public:
    Test(int a = 0)
        :_a(a)
    {
        cout << "Test():_a = " << _a << endl;
    }
    ~Test()
    {
        cout << "~Test()" << endl;
    }
};
int main()
{
    // 对于内置类型,new会调用其默认构造函数
    // delete会调用其析构函数
    Test* ptest1 = new Test;
    delete ptest1;
    cout << endl;

    // 也可以对其进行初始化赋值
    Test* ptest2 = new Test(20);
    delete ptest2;
    cout << endl;

    // 开辟一块连续的自定义类型的空间
    // new会调用n次默认构造函数,delete会调用n次析构函数
    Test* ptest3 = new Test[5];
    delete[] ptest3;
    cout << endl;

    // 开辟一块连续空间并初始化
    Test* ptest4 = new Test[5]{ 1,2,3 };
    delete[] ptest4;
    cout << endl;

    return 0;
}

三、operator new与operator delete

new与delete是C++中的两个关键字,其实现的原理是通过调用对应的函数。

operator new是一个C++中的一个全局函数(不是运算符重载!)。当使用new的时候,会调用operator new函数,其参数是要开辟空间的大小,用malloc申请空间,申请成功就返回首地址,申请失败则抛出一个异常(异常先暂时了解)。

operator delete也是一个全局函数,内部实现最终是调用free释放空间。

四、定位new表达式

定位new表达式实在已经分配好的空间中调用构造函数初始化一个对象。

class Test
{
    // 为了演示方便,将成员变量设置为public
public:
    int _a;

    Test(int a = 0)
        :_a(a)
    {
        cout << "Test():_a = " << _a << endl;
    }
    ~Test()
    {
        cout << "~Test()" << endl;
    }
};
int main()
{
    // 这样申请的空间并不会对这块空间初始化
    Test* ptest1 = (Test*)malloc(sizeof(Test));
    cout << ptest1->_a << endl << endl;

    // 构造函数不能显示调用,下面的语句会报错
    //ptest1->Test();
    free(ptest1);
    
    // 第一次打印应为随机值
    Test* ptest2 = (Test*)malloc(sizeof(Test));
    cout << ptest2->_a << endl;

    // 通过定位 new 表达式调用构造函数之后,打印应为 0
    new(ptest2)Test();
    cout << ptest2->_a << endl;
    ptest2->~Test();
    free(ptest2);
    cout << endl;


    // 也可以传值调用构造函数
    Test* ptest3 = (Test*)malloc(sizeof(Test));
    new(ptest3)Test(10);
    cout << ptest3->_a << endl;
    ptest3->~Test();
    free(ptest2);

    return 0;
}

五、内存泄漏

通俗一点的内存泄露,就是在申请了空间之后,丢失的该空间的指针,从而无法释放这一块空间,导致其他程序也无法使用这一块空间,就称为内存泄漏。

int a = 0;
int* p = new int[10];
p = &a;

在上述的代码中,new int[10]申请的40个字节的空间的指针丢了,导致无法释放这一块空间。

内存泄漏可能会导致程序运行过程中可使用的内存空间越来越少,导致程序变得卡顿,直至崩溃。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

王红花x

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值