C++中的new和delete

相关文章

C++智能指针


文章目录

  • 相关文章
  • 前言
  • [一、new 运算符](#一、new 运算符)
    • [1. operator new 函数的范围](#1. operator new 函数的范围)
    • [2. 在类中重载new运算符](#2. 在类中重载new运算符)
    • [3. 分配失败](#3. 分配失败)
  • [二、delete 运算符](#二、delete 运算符)
    • [1. 内存泄露统计示例](#1. 内存泄露统计示例)
    • [2. 在类中重载delete运算符](#2. 在类中重载delete运算符)
  • 总结

前言

在C++中,new和delete是用于动态内存管理的运算符,它们允许程序在运行时动态地分配和释放内存,而不需要在编译时知道确切的内存需求。动态内存分配是指在程序运行时根据需要分配内存空间,而静态内存分配是指在编译时分配内存空间。new和delete是C++中实现动态内存分配和释放的关键工具。

new运算符用于在堆上动态分配内存。它可以用于分配单个对象或数组。当使用new来分配单个对象时,它会返回一个指向所分配内存空间的指针,并自动调用对象的构造函数来初始化对象。当使用new来分配数组时,它会分配足够的内存来存储整个数组,并返回指向数组第一个元素的指针。这样,程序可以根据需要动态地创建数组,而不需要在编译时知道数组的大小。

delete运算符用于释放由new分配的内存。对于单个对象,使用delete;对于数组,使用delete[]。当不再需要动态分配的内存时,应该使用delete来释放内存,以防止内存泄漏。delete会调用对象的析构函数来清理对象,并释放所分配的内存。这样,程序可以在不需要内存时及时释放它,以避免内存资源的浪费。

new和delete提供了灵活的内存管理机制,使程序能够根据需要动态地分配和释放内存。然而,它们需要谨慎使用,因为错误的使用可能导致内存泄漏、悬空指针等问题。例如,在使用new分配内存后,如果忘记使用delete释放内存,就会导致内存泄漏;而在使用delete释放内存后,如果继续使用指向已释放内存的指针,就会导致悬空指针问题。因此,在使用new和delete时,需要确保正确地匹配内存的分配和释放,并避免出现悬空指针的情况。


C++ 支持使用 new 和 delete 运算符动态分配和解除分配对象。 这些运算符为来自称为"自由存储"(也称为"堆")的池中的对象分配内存。 new 运算符调用特殊函数 operator new,delete 运算符调用特殊函数 operator delete。

一、new 运算符

operator new的第一个参数必须为 size_t 类型,且返回类型始终为 void*,编译器将如下语句转换为对函数 operator new 的调用:

cpp 复制代码
char *p = new char[64];

重复调用 operator new 会返回不同的地址(指针)。

如果要申请的的存储空间为零字节,operator new 将返回指向不同对象的指针:

cpp 复制代码
#include <iostream>
using namespace std;

int main()
{
	char *p1 = new char[0];
	char *p2 = new char[0];
	char *p3 = new char[0];
	cout << "p1=0x" << (int*)p1 << endl;
	cout << "p2=0x" << (int*)p2 << endl;
	cout << "p3=0x" << (int*)p3 << endl;
    return 0;
}

如果分配请求的内存不足,operator new 会引发 std::bad_alloc 异常。 或者,如果使用了 placement 形式 new(std::nothrow),或者链接在非引发的 operator new 支持中,它将返回 nullptr

1. operator new 函数的范围

运算符 范围
::operator new 全局
class-name::operator new

在使用 new 运算符分配内置类型的对象、不包含用户定义的 operator new 函数的类类型的对象和任何类型的数组时,将调用全局 operator new 函数。 在使用 new 运算符分配类类型的对象时(其中定义了 operator new),将调用该类的 operator new

2. 在类中重载new运算符

示例:

cpp 复制代码
#include <memory.h>
#include <iostream>
using namespace std;

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

	void *operator new(size_t size)
	{
		//可以自定义空间申请规则
		cout << "operator new" << endl;
		return malloc(size);
	}
};

int main()
{
	Test *p = new Test;
	return 0;
}

执行结果:

执行流程:

在类声明中支持数组的 new 运算符。 例如:

cpp 复制代码
#include <memory.h>
#include <iostream>
using namespace std;

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

	void *operator new[](size_t size)
	{
		cout << "operator new[]" << endl;
		return malloc(size);
	}
};

int main()
{
	Test *p = new Test[5];
	return 0;
}

执行结果:

3. 分配失败

C++ 标准库中的 new 函数支持自 C++98 以来在 C++ 标准中指定的行为。 如果分配请求的内存不足,operator new 会引发 std::bad_alloc 异常。标准 C++ 要求分配器引发 std::bad_alloc 或派生自 std::bad_alloc 的类。 可以处理此类异常,如以下示例所示:

cpp 复制代码
#include <iostream>
using namespace std;
 
int main()
{
	size_t n = 20000000000L;
	try {
		int *p = new int[n];
		cout << p << endl;
	}
	catch (bad_alloc& ex) {
		cout << "申请内存失败: " << ex.what() << endl;
	}
	return 0;
}

执行结果:

二、delete 运算符

可使用 delete 运算符释放使用 new 运算符动态分配的内存。 delete 运算符调用 operator delete 函数,该函数将内存释放回可用池。 使用 delete 运算符也会导致调用类析构函数(如果存在)。

1. 内存泄露统计示例

能过自定义 operator newoperator delete 函数,来记录申请内存和释放的次数,判断是否存在内存泄露,示例如下:

cpp 复制代码
#include <iostream>
using namespace std;

bool bLog = 0;
int  nAllocated = 0;

void *operator new(size_t size) { 
	++nAllocated;
	cout << "申请内存 " << nAllocated
		<< " 大小 " << size
		<< "\n";
	return malloc(size);
}

void operator delete(void *p) {
	--nAllocated;
	clog << "释放内存 " << nAllocated
		<< "\n";
	free(p);
}

int main() {
	for (int i = 0; i < 10; ++i) {
		char *p = new char[10];
		delete[] p;
	}

	cout << nAllocated << endl;
	return 0;
}

2. 在类中重载delete运算符

示例如下:

cpp 复制代码
#include <iostream>
using namespace std;

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

	~Test() {
		cout << "~Test()" << endl;
	}

	void *operator new(size_t size)
	{
		cout << "operator new" << endl;
		return malloc(size);
	}

	void *operator new[](size_t size)
	{
		cout << "operator new[]" << endl;
		return malloc(size);
	}

	void operator delete (void* p) {
		cout << "operator delete(void*)" << endl;
		free(p);
	}

	void operator delete[](void* p) {
		cout << "operator delete[](void*)" << endl;
		free(p);
	}

};

int main() {
	Test *p1 = new Test;
	delete p1;

	cout << "------------------\n";
	Test *p2 = new Test[5];
	delete[] p2;
	return 0;
}

执行结果:

执行过程:


总结

new和delete是C++中用于动态内存管理的运算符,它们提供了灵活的内存分配和释放机制,但需要谨慎使用以避免内存泄漏和悬空指针等问题。随着智能指针的引入,程序员可以更安全地进行动态内存管理,减少了对new和delete的直接使用,提高了程序的可靠性和可维护性。


✍结尾 ❤️ 感谢您的支持和鼓励关注不迷路✍

相关推荐
whp40415 分钟前
springboot静态资源映射不生效问题
java·spring boot·后端
一丝晨光15 分钟前
Objective-C 1.0和2.0有什么区别?
java·开发语言·macos·c#·objective-c·swift·apple
Kika写代码20 分钟前
【基于轻量型架构的WEB开发】课程 作业4 AOP
java·前端·架构
游王子1 小时前
LocalDate和LocalDateTime类
java·开发语言
程序猿小柒1 小时前
leetcode hot100【LeetCode 79.单词搜索】java实现
java·算法·leetcode
waterme1onY1 小时前
Library:Day-02
java
一个儒雅随和的男子1 小时前
告别重启大法,CPU飙高问题如何排查详细教程以及解决方案
java·jvm
何曾参静谧4 小时前
「C/C++」C/C++STL篇 之 数组赋值给std::vector多种方法
c语言·开发语言·c++
惜.己4 小时前
Jmeter的安装,设置中文,解决乱码问题
java·测试工具·jmeter·jdk·1024程序员节
q567315234 小时前
如何在下载我上传的数据时自动设置 Content-Type
java·开发语言·python·缓存·命令模式