new || operator new || placement new || allocator的联系与区别

本文介绍了C++中new操作符的工作原理,包括operator new用于分配内存、placement new用于对象初始化的过程。并通过实例展示了如何使用这两种机制。

@ new

我们通常使用:

new AA 或 new AA[n]

在堆上动态生成对象。事实上,此处的new 是 类AA的操作符(operator)。它其实分为三个步骤:

1. 申请堆内存空间;

2. 初始化对象;

3. 返回对象指针。

 

@ operator new

operator new为一个全局函数,其原型:

void* operator new(std::size_t size)

operator new的作用是分配size数目byte的内存,并返回指向该原始内存的空指针。

使用方法:

operator new(n) 或 ::operator new(n)

 

@ placement new

placement new用来对原始内存进行初始化,其具有全局版本,原型:

void* operator new(std::size_t size, void* ptr)

使用方法是:

new(ptr) AA 或 ::new(ptr) AA 或 ::new(ptr) AA[n], 其中ptr是原始内存的地址

 

我们对operator new 和 placement new 举个例子:

void* ptr = ::operator new(20);

int* intPtr = new(ptr) int(3);

该例子通过operator new申请了20个byte的原始内存,然后在原始内存上,placement new初始化了一个值为3的int对象。

 

通过以上描述,我们大概已经知道,@new的功能可以通过@operator new 和placement new结合实现。事实上,类AA的new操作符重载正是通过这种方式实现。

此处我们需要说明的是,@new是无法重载的,我们只能重载它的第一步@operator new,第二步初始化内存也无法重载,是编译器自动调用构造函数。

class AA
{
public:
	// @ new
	void* operator new(size_t size /* , 其它参数 */) // size为字节大小
	{
		cout << "size: " << size << endl;

		// @ operator new, 需指定全局域,否则会调用AA的new,形成递归
		void* ptr = ::operator new(size);

		// @ placement new, 需指定全局域,否则默认为AA的new,但AA无此版本new,所以会报错
		return ptr;
	}
};


int main()
{
	new AA; // 当我们使用new时,其返回大小给operator new, operator new申请内存,然后自动调用构造函数初始化该内存,并返回指针

	system("pause");
	return 0;
}

可见我们可以对类的@new进行定制,当然我们也可以重载@new[]版本,其中@new的形参size即我们使用@new的输入参数:

new AA : size为 1 x 对象大小

new AA[n]:size为 n x 对象大小

 

@ allocator

allocator也实现了内存申请和初始化的分离,但其内存申请时,是按sizeof(AA)为单位进行申请的,粒度更大;@operator new是按byte为单位申请的。

 

 

/* 注意 */

@placement new只是调用构造函数初始化了对象,相应的我们只需要执行析构函数,而不需要delete,否则有可能多次delete;

@operator new申请了内存,所以相应的应该调用delete释放内存。

 

 

 

<think>好的,我现在要回答用户关于C++中newmalloc、deletefree区别的问题。首先,我需要回忆自己之前学过的相关知识,确保信息准确。然后,按照用户的要求,结构要清晰,分步骤解释,同时引用提供的资料中的相关内容。 首先,new和malloc都是用于动态内存分配,但它们在C++中有很多不同。我应该从以下几个方面来比较:语法、构造函数调用、类型安全、内存大小计算、错误处理、重载可能性以及内存来源等方面。同样,delete和free的区别也需要涵盖析构函数调用和内存释放的细节。 接下来,我需要检查用户提供的引用内容,看看是否有可以引用的地方。引用[1]中提到了使用malloc_allocator的vector,这可能内存分配器有关,但不确定是否直接相关。引用[2]是关于宏扩展和编译的示例,可能和内存管理关系不大,但需要留意是否有相关内容。看起来这两个引用可能不是直接回答问题的关键,但或许可以在讨论底层实现时提及。 然后,我需要确保使用正确的中文表达,行内公式用$...$,独立公式用$$...$$。不过在这个问题中,可能涉及到的数学公式不多,但如果有提到内存分配的大小计算,可能需要用到。比如,使用malloc时计算数组大小的例子,可以写成$sizeof(int) * n$。 另外,用户要求生成相关问题,我需要根据回答的内容,提出几个相关的问题,比如内存泄漏处理、异常安全、placement new的使用等。 现在,开始组织内容: 1. 语法差异:new是运算符,malloc是函数。例如,int *p = new int; vs int *p = (int*)malloc(sizeof(int)); 2. 构造函数和析构函数:new会调用构造函数,delete调用析构函数,而malloc/free不会。这一点很重要,特别是对于带有资源管理的对象,比如类中有文件句柄或锁的情况。 3. 类型安全:new返回正确类型的指针,不需要强制转换;malloc返回void*,需要显式转换。 4. 内存大小计算:malloc需要手动计算字节数,比如分配10个int:malloc(sizeof(int)*10),而new直接写new int[10]。 5. 错误处理:new在分配失败时抛出std::bad_alloc异常,而malloc返回NULL,需要检查返回值。 6. 重载:可以重载类的operator newoperator delete,而malloc/free不能重载。 7. 内存来源:new从自由存储区分配,malloc从堆分配,但具体实现可能相关,这里可能需要引用[1]提到的分配器,比如malloc_allocator,说明不同分配器的使用情况。 关于引用部分,引用[1]中的std::vector使用malloc_allocator,可能说明C++中容器可以自定义分配器,而默认情况下vector使用new/delete,但用户可以通过分配器选择使用malloc/free。这一点可以作为扩展内容提及,说明在特定情况下,用户可能需要替换默认的内存管理方式。 引用[2]中的例子涉及预处理和编译过程,可能和内存管理关系不大,暂时不考虑引用。 在回答时,需要确保每个区别点清晰,并且举例说明。例如,在构造函数调用方面,可以举一个类的例子,用new创建对象时会调用构造函数,而malloc不会,可能导致对象状态不正确。 最后,生成相关问题,比如new和malloc的底层实现差异,如何避免内存泄漏,智能指针如何管理内存等。 需要避免错误,比如不要混淆自由存储区(free store)和堆(heap),虽然有时实现可能将两者视为同一区域,但标准中它们是不同的概念。另外,确保提到delete和free不能混用,否则可能导致未定义行为,比如用free释放new分配的内存,或者用delete释放malloc分配的内存。 总结一下,回答的结构应该是先概述主要区别,然后分点详细说明,每个点举例并必要时引用资料,最后提出相关问题。</think>在C++中,`new`/`delete``malloc`/`free`均用于动态内存管理,但存在以下核心区别: --- ### 1. **语法类型安全** - **`new`/`delete`** 是运算符,直接关联类型: ```cpp int* p = new int(5); // 分配并初始化int为5 delete p; // 释放内存 ``` - 类型安全:`new`返回正确类型的指针,无需强制转换。 - **`malloc`/`free`** 是函数,需手动计算字节数并类型转换: ```cpp int* p = (int*)malloc(sizeof(int)); // 显式转换且未初始化 free(p); ``` --- ### 2. **构造析构函数** - **`new`** 调用构造函数: ```cpp class MyClass { /* 构造函数和成员 */ }; MyClass* obj = new MyClass(); // 调用构造函数 ``` - **`delete`** 调用析构函数: ```cpp delete obj; // 调用析构函数后释放内存 ``` - **`malloc`/`free`** 仅分配/释放内存,**不调用构造/析构函数**,可能导致资源泄漏(如未关闭文件)[^1]。 --- ### 3. **内存分配失败处理** - **`new`** 失败时抛出`std::bad_alloc`异常,需用`try-catch`捕获: ```cpp try { int* p = new int[10000000000]; } catch (const std::bad_alloc& e) { // 处理异常 } ``` - **`malloc`** 失败返回`NULL`,需显式检查: ```cpp int* p = (int*)malloc(10000000000); if (!p) { /* 处理错误 */ } ``` --- ### 4. **内存大小计算** - **`malloc`** 需手动计算字节数: ```cpp int* arr = (int*)malloc(10 * sizeof(int)); // $10 \times \text{sizeof(int)}$ ``` - **`new`** 自动推导类型大小: ```cpp int* arr = new int[10]; // 直接指定元素数量 ``` --- ### 5. **重载扩展性** - **`new`/`delete`** 可重载,支持定制内存管理策略: ```cpp void* operator new(size_t size) { /* 自定义逻辑 */ } ``` - **`malloc`/`free`** 不可重载,行为固定。 --- ### 6. **内存来源** - **`new`** 从**自由存储区(free store)**分配内存,具体实现可能依赖编译器。 - **`malloc`** 从**堆(heap)**分配,属于C运行时库管理。 - C++容器(如`std::vector`)可通过分配器(如`malloc_allocator`)选择底层内存来源。 --- ### 错误使用示例 - **混用导致未定义行为**: ```cpp int* p = new int; free(p); // 错误!应使用delete int* q = (int*)malloc(sizeof(int)); delete q; // 错误!应使用free ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值