c++ new 重载

当写出
p = new P();
这样的代码的时候, 实际上有两步操作, 首先分配内存,
然后在分配好的内存之上初始化类成员.

第二步是有构造函数完成的, 第一步就是new函数的工作.

全局的new有六种重载形式, 
void *operator new(std::size_t count)
    throw(std::bad_alloc);             //一般的版本

void *operator new(std::size_t count,  //兼容早版本的new
    const std::nothrow_t&) throw();    //内存分配失败不会抛出异常

void *operator new(std::size_t count, void *ptr) throw();
                                       //placement版本
void *operator new[](std::size_t count)  //
    throw(std::bad_alloc);

void *operator new[](std::size_t count,  //
    const std::nothrow_t&) throw();

void *operator new[](std::size_t count, void *ptr) throw();

所以, 刚才的用法, 就是使用new函数的一种重载形式.
如果A这个对象以同样实行重载了new函数的化, 作为成员函数
会被优先调用.
 
C++的各种new简介

1.new T

第一种new最简单,调用类的(如果重载了的话)或者全局的operator new分配空间,然后用
类型后面列的参数来调用构造函数,用法是
new TypeName(initial_args_list). 如果没有参数,括号一般可以省略.例如

int *p=new int;
int *p=new int(10);
int *p=new foo("hello");

通过调用delete来销毁:
delete p;

2. new T[]
这种new用来创建一个动态的对象数组,他会调用对象的operator new[]来分配内存(如果
没有则调用operator new,搜索顺序同上),然后调用对象的默认构造函数初始化每个对象
用法:
new TypeName[num_of_objects];
例如
int *p= new int[10];
销毁时使用operator delete[]

3.new()T 和new() T[ ]
这是个带参数的new,这种形式的new会调用operator new(size_t,OtherType)来分配内存
这里的OtherType要和new括号里的参数的类型兼容,

这种语法通常用来在某个特定的地址构件对象,称为placement new,前提是operator new
(size_t,void*)已经定义,通常编译器已经提供了一个实现,包含<new>头文件即可,这个
实现只是简单的把参数的指定的地址返回,因而new()运算符就会在括号里的地址上创建
对象

需要说明的是,第二个参数不是一定要是void*,可以识别的合法类型,这时候由C++的重载
机制来决定调用那个operator new

当然,我们可以提供自己的operator new(size_,Type),来决定new的行为,比如
char data[1000][sizeof(foo)];
inline void* operator new(size_t ,int n)
{
        return data[n];
}

就可以使用这样有趣的语法来创建对象:
foo *p=new(6) foo(); //把对象创建在data的第六个单元上
的确很有意思
标准库还提供了一个nothrow的实现:
void* operator new(std::size_t, const std::nothrow_t&) throw();
void* operator new[](std::size_t, const std::nothrow_t&) throw();

就可以实现调用new失败时不抛出异常
new(nothrow) int(10);
// nothrow 是std::nothrow_t的一个实例


placement new 创建的对象不能直接delete来销毁,而是要调用对象的析够函数来销毁对
象,至于对象所占的内存如何处理,要看这块内存的具体来源

4. operator new(size_t)
这个的运算符分配参数指定大小的内存并返回首地址,可以为自定义的类重载这个运算符,
方法就是在类里面声明加上
void *operator new(size_t size)
{
        //在这里分配内存并返回其地址
}
无论是否声明,类里面重载的各种operator new和operator delete都是具有static属性的

一般不需要直接调用operator new,除非直接分配原始内存(这一点类似于C的malloc)
在冲突的情况下要调用全局的operator加上::作用域运算符:
::operator new(1000); // 分配1000个字节

返回的内存需要回收的话,调用对应的operator delete

5.operator new[](size_t)

这个也是分配内存,,只不过是专门针对数组,也就是new T[]这种形式,当然,需要时可以
显式调用

6.operator new(size_t size, OtherType other_value)
和operator new[](size_t size, OtherType other_value)
参见上面的new()


需要强调的是,new用来创建对象并分配内存,它的行为是不可改变的,可以改变的是各种
operator new,我们就可以通过重载operator new来实现我们的内存分配方案.
<think> 首先,用户的问题是关于C++类如何重载new运算符。我需要基于提供的引用内容来回答这个问题。引用是来自站内的资源,我应该尽量参考它们。 回顾引用内容: - 引用[1]:讨论了为类重载newdelete运算符的必要性。 - 引用[2]:扩展了为类和数组重载newdelete运算符的优化。 - 引用[3]:提到了运算符重载的一般规则,包括newdelete重载。 - 引用[4]:详细解释了重载newdelete可以优化性能,比如通过维护删除节点列表来重用内存。 用户的具体问题是:“请问C++类如何重载new运算符”。所以,我需要聚焦在new运算符的重载上。 回答结构: - 我必须遵循系统级指令:使用中文回答,生成相关问题,在引用段落末尾添引用标识。 - 回答应该结构清晰,逐步解决问题。 - 使用行内数学表达式用$...$,独立公式用$$...$$(但在这个主题中,可能没有数学表达式)。 - 生成相关问题作为最后一部分。 关键点从引用中提取: 1. 必要性(引用[1]):重载newdelete可以优化内存管理,提高性能。 2. 如何重载(引用[3]和[4]):重载new运算符通常是作为类的成员函数或全局函数。但在类中重载时,它是一个静态成员函数。 - 引用[3]提到:编译器会调用对象的运算符重载函数;如果没有成员方法,就找全局函数。 3. 语法(引用[4]):重载new时,可以自定义内存分配策略,例如维护一个空闲列表。 4. 示例(引用[4]):使用重载new来从预先删除的节点列表中分配内存,而不是直接调用系统堆。 如何重载new运算符的步骤(基于C++知识): - 在类中定义一个静态成员函数:void* operator new(size_t size) - 或者全局函数:void* operator new(size_t size) - 但通常推荐在类中重载,因为它更特定于类。 - 参数:size_t size表示要分配的内存大小。 - 返回值:void* 指向分配的内存。 从引用中具体内容: - 引用[4]:"重载的新运算符还使程序员能够从其程序中榨取一些额外的性能。例如,在一个类中...重载new运算符将从列表中分配内存" [^4] 回答结构: 1. 介绍重载new运算符的目的。 2. 说明如何在类中重载。 3. 提供一个简单的代码示例。 4. 解释好处。 5. 结束时生成相关问题。 生成相关问题: - 基于指令:生成3-4个相关问题。 - 例如: 1. 重载delete运算符时需要注意什么? 2. 如何为数组重载newdelete运算符? 3. 重载new运算符的性能优化策略有哪些? 4. 在哪些场景下应该重载newdelete运算符? 确保引用标识: - 当引用内容时,在段落末尾添[^编号],如[^1]。 最终回答框架: - 第一段:解释重载new运算符的重要性(参考引用[1]和[4])。 - 第二段:详细步骤如何重载(参考引用[3]和[4])。 - 第三段:代码示例(简单但有效)。 - 第四段:总结好处。 - 最后:生成相关问题。 </think> ### C++类如何重载new运算符 在C++中,重载`new`运算符允许你为特定类自定义内存分配逻辑,从而提高程序性能、减少内存碎片或实现特殊的内存管理策略(如对象池)。这是通过为类定义静态成员函数`operator new`来实现的。以下步骤基于站内引用内容详细说明: 1. **重载的必要性** 重载`new`运算符可以优化内存管理。例如,在一个频繁创建和销毁对象的类中,你可以维护一个空闲对象列表,通过重载`new`直接从列表中分配内存,避免频繁调用系统堆分配器。这能显著提升性能并减少内存碎片问题[^1][^4]。 2. **重载的基本语法** `new`运算符的重载必须定义为类的静态成员函数(因为内存分配不依赖于特定对象实例)。函数签名固定为: ```cpp static void* operator new(size_t size); ``` - `size_t size`:编译器自动传入的字节大小(通常为类的大小)。 - 返回值:一个`void*`指针,指向分配的内存块。 编译器在创建对象时会优先调用这个重载版本,而不是全局的`new`运算符[^3]。 3. **实现步骤与示例代码** - **步骤**: - 在类声明中定义`static void* operator new(size_t size)`。 - 在实现中,使用自定义逻辑分配内存(如从预分配池中获取)。 - 如果需要,可以重载对应的`delete`运算符以确保内存正确释放。 - **简单示例**: 以下代码展示如何为一个`MyClass`类重载`new`运算符,使用一个简单的空闲列表来重用内存: ```cpp #include <iostream> #include <cstdlib> class MyClass { public: // 重载new运算符 static void* operator new(size_t size) { if (freeList == nullptr) { // 空闲列表为空时,从系统堆分配 return ::operator new(size); } else { // 从空闲列表中复用内存 void* ptr = freeList; freeList = freeList->next; return ptr; } } // 重载delete运算符(可选,但推荐配对实现) static void operator delete(void* ptr) { // 将内存块入空闲列表以供复用 Node* node = static_cast<Node*>(ptr); node->next = freeList; freeList = node; } // 类其他成员... private: struct Node { Node* next; }; static Node* freeList; // 空闲列表头指针 }; // 初始化静态成员 MyClass::Node* MyClass::freeList = nullptr; ``` 在此示例中: - 当调用`new MyClass`时,会优先使用重载的`operator new`。 - 如果空闲列表为空,则回退到全局`::operator new`。 - 重载的`delete`将释放的内存入空闲列表,优化后续分配[^4]。 4. **注意事项与最佳实践** - **静态成员**:`operator new`必须是`static`的,因为它不依赖于对象实例。 - **配对实现**:强烈建议同时重载`operator delete`,以避免内存泄漏或不匹配的释放逻辑[^2]。 - **性能优化**:如引用所述,这种技术常用于高性能场景(如游戏引擎或实时系统),通过减少堆分配开销提升效率[^4]。 - **兼容性**:重载仅影响该类及其派生类,全局`new`保持不变[^3]。 通过自定义`new`运算符,你可以为类实现高效、灵活的内存管理策略,这在资源受限的环境中尤为重要[^1][^2]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值