operator new与new operator

本文解析了C++中operatornew与newoperator的区别,前者仅分配内存而不调用构造函数,后者则同时完成内存分配与对象构造。并通过实例展示了如何重载operatornew以实现定制化的内存管理。

C++中的operator newnew operator,看上去挺像的两姐妹,却有天壤之别。
operator new
(1)       只分配所要求的空间,不调用相关对象的构造函数。当无法满足所要求分配的空间时,则
        ->如果有new_handler,则调用new_handler,否则
        ->如果没要求不抛出异常(以nothrow参数表达),则执行bad_alloc异常,否则
        ->返回0
(2)       可以被重载
(3)       重载时,返回类型必须声明为void*
(4)       重载时,第一个参数类型必须为表达要求分配空间的大小(字节),类型为size_t
(5)       重载时,可以带其它参数
 
new operator
(1)       调用operator new分配足够的空间,并调用相关对象的构造函数
(2)       不可以被重载
 
相应地,operator deletedelete operator有相似的特性。
 
举个例子
 
class X 
{
public:
…………
    static void* operator new(size_t size)
{
    return ::operator new(size);
}

static void operator delete(void* pointee)
{
    ::operator delete(pointee);
}
…………
};

X* px = new X();
该行代码中的newnew operator,它将调用类X中的operator new,为该类的对象分配空间,然后调用当前实例的构造函数。
 
delete px;
该行代码中的deletedelete operator,它将调用该实例的析构函数,然后调用类X中的operator delete,以释放该实例占用的空间。
 
new operatordelete operator的行为是不能够也不应该被改变,这是C++标准作出的承诺。而operator newoperator deleteC语言中的mallocfree对应,只负责分配及释放空间。但使用operator new分配的空间必须使用operator delete来释放,而不能使用free,因为它们对内存使用的登记方式不同。反过来亦是一样。
 
你可以重载operator newoperator delete以实现对内存管理的不同要求,但你不能重载new operatordelete operator以改变它们的行为。
 
当重载operator new时,可以提供更多的参数,在new一个对象时,通过在关键字new后的括号传递额外的参数。比如以下的类
 
class A 
{
public:
    …………
    static void* operator new(size_t size, const string& example)
{
    cout << example << endl;
    return ::operator new(size);
}
…………
};

A* pa = new (“This will be printed out in operator new”) A();
新标准的C++允许以这样的方式传递一个名为nothrow的参数,以表明当为该对象分配空间失败时,不抛出异常,而是返回0,以兼容旧标准new的行为。比如
 
class B {};

B* pb = new (nothrow) B();
当然这只能对那些使用默认operator new操作符的类。对已经重载了operator new的类(比如上面的XA),如果不声明能接受nothrow参数,自然无法享受C++标准带来的礼物。
<think> 我们正在讨论C++中的内存管理函数。用户之前询问了`malloc`、`calloc`、`realloc`和`free`的区别,现在转向C++的`operator new`和`operator delete`。根据引用内容,我们需要区分这些操作符和函数。 关键点: - `operator new`和`operator delete`是内存分配和释放的函数,类似于C的`malloc`和`free`,但它们是C++中用于动态内存管理的底层函数。 - `new operator`(即`new`表达式)和`delete operator`(即`delete`表达式)是C++中的关键字,它们不仅分配/释放内存,还调用构造函数/析构函数。 根据引用[2]:`delete operator`在释放内存的基础上还调用析构函数,而`operator delete`只是释放内存。 引用[4]进一步说明:`new operator`和`delete operator`在堆上分配内存并构造对象(或销毁对象并释放内存),而`operator new`和`operator delete`仅仅是分配和释放内存。 此外,引用[5]指出,存在两种形式的`operator new`和`operator delete`:一种用于单个对象,另一种用于数组。它们的函数原型如下: ```cpp void* operator new(size_t); // 分配一个对象 void* operator new[](size_t); // 分配一个数组 void operator delete(void*); // 释放一个对象 void operator delete[](void*); // 释放一个数组 ``` 因此,我们需要区分: 1. `operator new`和`operator delete`函数:负责原始内存的分配和释放。 2. `new`表达式(`new operator`)和`delete`表达式(`delete operator`):它们除了调用`operator new`和`operator delete`之外,还会调用构造函数和析构函数。 具体区别如下: ### 1. `operator new` 和 `operator delete` - 是函数,可以被重载(全局或类特定的重载)。 - 只负责内存的分配和释放,不涉及对象构造和析构。 - 分配内存时,使用`operator new`函数;释放内存时,使用`operator delete`函数。 - 分配内存的大小由参数指定(单位字节)。 ### 2. `new`表达式和`delete`表达式 - `new`表达式:先调用`operator new`分配内存,然后在分配的内存上调用构造函数初始化对象。 例如:`MyClass* obj = new MyClass();` 分解为: 1. 调用`operator new(sizeof(MyClass))`分配内存。 2. 在分配的内存上调用`MyClass`的构造函数。 - `delete`表达式:先调用析构函数销毁对象,然后调用`operator delete`释放内存。 例如:`delete obj;` 分解为: 1. 调用`obj`指向对象的析构函数。 2. 调用`operator delete(obj)`释放内存。 ### 3. 数组版本 - 对于数组,有`new[]`和`delete[]`表达式,对应调用`operator new[]`和`operator delete[]`函数。 - 使用`new[]`时,除了分配内存,还会对数组中的每个元素调用构造函数(从第0个到最后一个)。 - 使用`delete[]`时,会对数组中的每个元素调用析构函数(顺序相反),然后释放内存。 ### 区别总结表 | 特性 | `operator new`/`delete` | `new`/`delete`表达式 | |--------------------|--------------------------------|-----------------------------| | 功能 | 仅分配/释放原始内存 | 分配内存+构造对象/析构对象+释放内存 | | 是否可重载 | 是 | 不可重载,但底层调用可重载的函数 | | 调用构造函数/析构函数 | 否 | 是 | | 数组形式 | `operator new[]`/`delete[]` | `new[]`/`delete[]` | ### 示例代码 ```cpp #include <iostream> #include <cstdlib> using namespace std; class MyClass { public: MyClass() { cout << "Constructor called" << endl; } ~MyClass() { cout << "Destructor called" << endl; } }; int main() { // 使用operator new分配内存,不调用构造函数 MyClass* p1 = static_cast<MyClass*>(operator new(sizeof(MyClass))); // 使用new表达式,分配内存并构造对象 MyClass* p2 = new MyClass(); // 显式调用构造函数(不推荐,但可以使用placement newnew(p1) MyClass(); // 在已分配的内存上构造对象 // 使用delete表达式:析构并释放 delete p2; // 输出: Destructor called // 先显式调用析构函数,再用operator delete释放 p1->~MyClass(); // 显式析构 operator delete(p1); // 释放内存,但不调用析构函数(因为已经显式调用) return 0; } ``` ### 注意事项 - 不要混淆`operator new`和`new`表达式:`operator new`只是一个内存分配函数,而`new`表达式是一个完整的对象创建操作。 - 重载`operator new`和`operator delete`可以用于自定义内存管理(如内存池),但需要谨慎处理。 - 使用`delete`表达式时必须`new`表达式匹配(例如,`new`分配的用`delete`,`new[]`分配的用`delete[]`),否则行为未定义。 §§相关问题§§ 1. 如何重载类专属的`operator new`和`operator delete`? 2. 什么是placement new,它有什么用途? 3. 为什么`delete`表达式需要知道要释放的内存大小? 4. 如何避免使用`new`和`delete`导致的内存泄漏? </think> ### `operator new` `operator delete` 函数的区别 `operator new` 和 `operator delete` 是 C++ 中的底层内存管理机制, `new operator`/`delete operator` 有本质区别: #### 1. **功能定位差异** | 函数 | 核心功能 | 是否调用构造/析构函数 | |------------------|----------------------------------|---------------------| | `operator new` | 仅分配原始内存块(类似`malloc`) | ❌ 不调用构造函数 | | `operator delete`| 仅释放原始内存块(类似`free`) | ❌ 不调用析构函数 | | `new operator` | 分配内存 + 调用构造函数 | ✅ 调用构造函数 | | `delete operator`| 调用析构函数 + 释放内存 | ✅ 调用析构函数 | #### 2. **语法重载机制** - **`operator new` 语法**: ```cpp void* operator new(size_t size); // 单对象版 void* operator new[](size_t size); // 数组版 ``` 分配 $size$ 字节的原始内存,返回 `void*`[^2][^4] - **`operator delete` 语法**: ```cpp void operator delete(void* ptr); // 单对象版 void operator delete[](void* ptr); // 数组版 ``` 释放由 `operator new` 分配的内存[^5] - **可重载性**: - 可全局重载或为特定类重载(实现自定义内存池)[^1] - 重载时需严格匹配函数签名 #### 3. ** new/delete 表达式的交互** 当使用 `new MyClass` 时: 1. 调用 `operator new(sizeof(MyClass))` 分配内存 2. 在返回地址上调用 `MyClass` 的构造函数 当使用 `delete ptr` 时: 1. 调用 `ptr->~MyClass()` 析构对象 2. 调用 `operator delete(ptr)` 释放内存[^2][^4] #### 4. **关键区别总结** | 特性 | `operator new/delete` | `new/delete operator` | |--------------------|----------------------------|----------------------------| | **内存操作** | 仅原始内存分配/释放 | 完整对象生命周期管理 | | **构造/析构调用** | 永不调用 | 总是调用 | | **使用场景** | 自定义内存分配策略 | 常规对象创建销毁 | | **重载影响范围** | 可类专属或全局重载 | 不可直接重载 | | **底层依赖** | 通常基于 `malloc` 实现 | 依赖 `operator new/delete` | #### 5. **实战示例** ```cpp #include <iostream> // 自定义 operator new(日志跟踪) void* operator new(size_t size) { std::cout << "Allocating " << size << " bytes\n"; return malloc(size); } // 自定义 operator delete void operator delete(void* ptr) noexcept { std::cout << "Releasing memory\n"; free(ptr); } class MyClass { public: MyClass() { std::cout << "Constructor\n"; } ~MyClass() { std::cout << "Destructor\n"; } }; int main() { MyClass* obj = new MyClass; // 输出:Allocating X bytes → Constructor delete obj; // 输出:Destructor → Releasing memory } ``` > ⚠️ **重要注意事项** > 1. 必须配对使用:`operator new` 分配的内存必须用 `operator delete` 释放 > 2. 数组版单对象版严格区分(`new[]` 对应 `delete[]`)[^5] > 3. 重载时需处理异常和边界条件 > 4. 不要混淆 `operator new` 和 `new operator` 的语义[^3]
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值