【C++】3-C/C++内存管理

【C++】3-C/C++内存管理

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

malloc/calloc/realloc/free,这里不再细述。

int main()
{
	// 动态申请4个整型大小的内存空间给ptr1
	int* ptr1 = (int*)malloc(sizeof(int) * 4);// 数组中元素值为随机值
	// 动态申请4个整型大小的内存空间给ptr2,并初始化为0
	int* ptr2 = (int*)calloc(4, sizeof(int)); // 数组中元素值为0
	// 对ptr2所指向的空间进行扩容,扩容到10个整型大小
	// 若空间足够,则原地扩容,在ptr2所指向的空间后面紧接着再开辟6个整型大小的空间,ptr2 == ptr3
	// 若空间不够,则异地扩容,在新位置重新开辟10个整型大小的空间给ptr3,并释放ptr2所指向的空间
	int* ptr3 = (int*)realloc(ptr2, sizeof(int) * 99999999999999);// 原来的空间值不变,新扩容的空间值为随机值

	return 0;
}

2. C++动态内存管理方式

C++使用new关键字动态申请空间,使用delete关键字释放动态申请的空间。

  • 对于内置类型,new/delete与malloc/free相比,只是用法上有所区别罢了
int main()
{
	// 内置类型
	// 相比于malloc/free,new和delete只是用法上有区别
	int* p1 = new int;// 默认不会初始化,是随机值
	delete p1;

	// 手动初始化
	int* p2 = new int(0);// 初始化为0
	delete p2;

	// 开辟3个int空间,即数组
	int* p3 = new int[3];// 默认不会初始化
	delete[] p3;// 数组释放要加[]

	// 初始化
	int* p4 = new int[3]{ 1,2,3 };
	delete[] p4;

	return 0;
}
  • 对于自定义类型,除了空间管理(开辟空间和释放空间)相同外,new会调用默认构造函数且delete会调用默认析构函数,而malloc和free则不会调用默认函数

    class A
    {
    public:
    	A(int a = 1)
    		: _a(a)
    	{
    		cout << "A()" << " " << _a << endl;
    	}
    	~A()
    	{
    		cout << "~A()" << endl;
    	}
    private:
    	int _a;
    };
    int main()
    {
        // 自定义类型
    	A* p1 = (A*)malloc(sizeof(A));
    	free(p1);
        cout << "-----" << endl;
    	A* p2 = new A;// 调用默认构造函数
    	delete p2;// 调用析构函数
    
    	return 0;
    }
    // 输出
    -----
    A() 1
    ~A()
    
  • 强烈建议new和delete要匹配。(即new单个类型空间,就用delete,new数组,就用delete[]。也不要new和delete与malloc和free混用)

    int main()
    {
        // 抵制下列写法,可能报错,也可能不报错
        // 一般情况,对于内置类型,正常运行;但对于自定义类型,可能会出现各种问题
        // 具体的依赖于编译器的实现机制
    	// 抵制1
    	int* p1 = new int;
    	delete[] p1;
    	// 抵制2
    	int* p2 = new int[3];
    	delete p2;
    	// 抵制3
    	int* p3 = new int;
    	free(p3);
    	// 抵制4
    	int* p4 = new int[3];
    	free(p4);
    	// 抵制5
    	int* p5 = (int*)malloc(sizeof(int));
    	delete p5;// 或者:delete[] p5
    	// 抵制6
    	int* p6 = (int*)malloc(sizeof(int) * 3);
    	delete[] p6;// 或者: delete p6
    
    	return 0;
    }
    

    若(对自定义类型开辟/释放空间)不匹配,具体报错与否取决于编译器的底层实现机制。

    (以下是vs2019编译器下执行)

    请添加图片描述

    请添加图片描述

  • new开辟空间失败,不会返回nullptr,而是会抛出一个异常(这里仅仅是提及)。

3. operator new和operator delete函数

  • new和delete是用户进行动态内存申请和释放的操作符
  • operator new 和operator delete是系统提供的全局函数,非重载(没有自定义类型参数)
  • new在底层调用operator new全局函数来申请空间,delete在底层通过operator delete全局函数来释放空间。
  • operator new底层是使用malloc申请空间,申请失败会抛异常(而非返回nullptr),operator delete底层是使用free释放空间

4. new和delete的底层实现

4.1 内置类型

对于内置类型,new和delete与malloc和free类似。只是:

  • new和delete开辟/释放的是单个元素的空间
  • new[]和delete[]开辟/释放的是一块连续的空间
  • new申请空间失败,会抛出异常,不返回nullptr;malloc则会返回nullptr(C语言为NULL)

4.2 自定义类型

对于自定义类型,new和delete除了开辟/释放空间,还会调用默认构造/析构函数。

具体原理如下:

  • new:
    1. 调用operator new函数动态申请单个元素的空间
    2. 若申请成功,调用默认构造函数对申请的空间初始化
  • delete:
    1. 调用默认析构函数对已经申请的空间进行清理
    2. 调用operator delete函数释放空间
  • new Type[N]:
    1. 调用operator new[]函数动态申请一块连续的空间(实际是在函数operator new[]中调用N次operator new函数)
    2. 若申请成功,调用N次默认构造函数对申请的连续空间的每一块单个元素的空间初始化
  • delete[]:
    1. 调用N次默认析构函数对申请的连续空间的每一块单个元素的空间清理
    2. 调用operator delete[]函数释放空间(实际是在函数operator delete[]中调用N次operator delete函数)

5. 定位new表达式(placement-new)

功能:在已经开辟(分配)好的空间中显式调用构造函数初始化对象(即对已经实例化的对象显式调用构造函数,进行初始化)。

语法:new(place_address) Typenew(place_address) Type(initializer-list)

​ place_address是一个指针,Type是自定义类型,initializer-list是自定义类型的初始化列表

**使用场景:**一般结合内存池使用,因为从内存池中分配出的内存没有被初始化,所以如果从内存池中分配出一块空间给一个自定义类型对象,就需要显式调用构造函数对其初始化(这里不细述)

class A
{
public:
	A(int a = 1, int b = 2)
		: _a(a)
		, _b(b)
	{
		cout << "A():" << this << " " << _a << endl;
	}
	~A()
	{
		cout << "~A():" << this << endl;
	}
private:
	int _a;
	int _b;
};
int main()
{
	// malloc可以理解为也是一个内存池
	A* p1 = (A*)malloc(sizeof(A));
	// 显式调用构造函数初始化p1指向的空间
	new(p1) A;// 不传参
	new(p1) A(5);// 传参1
	new(p1) A(10, 20);// 传参2
	// 上面三种定位new方式用一种即可

	p1->~A();// 析构函数可以直接显式调用
	free(p1);
	// 上面两行代码等价于:delete p1;

	return 0;
}


// 显式调用构造函数初始化p1指向的空间
	new(p1) A;// 不传参
	new(p1) A(5);// 传参1
	new(p1) A(10, 20);// 传参2
	// 上面三种定位new方式用一种即可

	p1->~A();// 析构函数可以直接显式调用
	free(p1);
	// 上面两行代码等价于:delete p1;

	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

丨归凡

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

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

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

打赏作者

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

抵扣说明:

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

余额充值