关于placement new

本文探讨了C++中的Placement New概念,通过分析Ogre引擎中的代码片段,详细解释了Placement New的用途及其实现方式,并对比了其与普通new操作符的区别。

    都说看别人写的代码是一件很痛苦的事情,最近为了自残竟一股劲的死磕Ogre的代码,当然是牺牲了千千万万的脑细胞而进展却异常的缓慢。两个星期过去了,竟没有放弃的念头,看来人是会有进步的。

    毕竟还是菜鸟,而面对C++的博大精深,难免很多不懂的地方。其中就包括placement new。先看看Ogre其中的一段代码:

#define OGRE_NEW_T(T, category) new (::Ogre::CategorisedAllocPolicy<category>::allocateBytes(sizeof(T), __FILE__, __LINE__, __FUNCTION__)) T

    简单来说,这是一个宏。难点从new开始,我们先了解一下new后面括号里的函数的作用,这是一个分配函数,主要的功能是分配T类型的大小空间并返回指向这个空间的指针。那么在new和T之间加上这个函数有什么用呢?

    为了这个问题,确实花费了我很少时间,终于黄天不负有心人,在仅有的网页中找到了这个概念——placement new,中文不知道怎样翻译,姑且称它为“定位new”。通常,new负责在对内存里找到一块能够满足要求的内存块。而placement new可以说是它的一种变体,它能指定要使用的内存位置。语法大致如下:

new (T* buffer) T

    buffer就是你要放置T的内存指针,然后new出来的对象T就会放在buffer所指向的指针。so easy!

     回到上面的宏,大概的工作过程就是先调用allocateBytes(sizeof(T), __FILE__, __LINE__, __FUNCTION__)分配空间,这个函数返回的指针就相当于上面buffer,然后new T就会从这个指针开始分配空间。

     暂时了解的一个区别是,placement new使用的是静态内存,因此不能用delete来释放内存。至于更多的区别,有待更加深入的了解。

     Ogre究竟为何要这样做?阿弥陀佛,参透中!!!!

### `operator new` 与 `placement new` 的区别及使用场景 在 C++ 中,`operator new` 和 `placement new` 是两个不同的概念,尽管它们都与内存分配和对象构造相关。理解它们的区别有助于更高效地管理内存和控制对象生命周期。 #### `operator new` `operator new` 是一个标准库函数,其主要职责是分配原始内存空间。它不涉及对象的构造过程。基本形式如下: ```cpp void* operator new(std::size_t size) throw(std::bad_alloc); ``` 当调用 `new` 表达式时,例如: ```cpp MyClass* obj = new MyClass(); ``` 编译器会隐式调用 `operator new(sizeof(MyClass))` 来分配内存,然后在该内存上调用构造函数来初始化对象[^4]。如果内存分配失败,`operator new` 会抛出 `std::bad_alloc` 异常,除非使用了 `nothrow` 版本。 用户可以重载 `operator new` 以实现自定义的内存分配策略。例如,在实现自定义内存池或容器类时,这种机制非常有用。通过重载,开发者可以控制内存分配行为,而不影响 `new` 表达式的语义。 #### `placement new` `placement new` 是 `operator new` 的一种特殊形式,用于在已分配的内存中构造对象。它的典型形式如下: ```cpp void* operator new(std::size_t, void* location); ``` 这个版本的 `operator new` 不会分配新的内存,而是返回传入的指针 `location`,即直接在指定的内存地址上构造对象[^1]。因此,它通常与手动内存管理结合使用,比如在预分配的缓冲区中构造对象。 使用 `placement new` 的典型方式如下: ```cpp char buffer[sizeof(MyClass)]; // 预分配内存 MyClass* obj = new(buffer) MyClass(); // 在 buffer 上构造对象 ``` 这种方式允许开发者精确控制对象的内存位置,适用于嵌入式系统、性能敏感的库(如 STL 容器)或需要严格内存对齐的场景。 需要注意的是,`placement new` 不可重载,因为它只是简单地返回传入的指针,不涉及内存分配逻辑。 #### 总结对比 | 特性 | `operator new` | `placement new` | |-----------------------|------------------------------------------|------------------------------------------| | 是否分配新内存 | 是 | 否(使用已有内存) | | 是否调用构造函数 | 否(仅分配内存) | 是(在已有内存上构造对象) | | 可否被重载 | 是 | 否 | | 典型用途 | 自定义内存分配策略、容器内部实现 | 在特定内存位置构造对象 | #### 示例代码 ```cpp #include <iostream> #include <new> // for placement new struct MyClass { int value; MyClass() : value(42) {} }; int main() { // 使用 operator new 分配内存 void* rawMemory = ::operator new(sizeof(MyClass)); // 使用 placement new 构造对象 MyClass* obj = new(rawMemory) MyClass(); std::cout << "Value: " << obj->value << std::endl; // 显式调用析构函数 obj->~MyClass(); // 释放原始内存 ::operator delete(rawMemory); } ``` 此示例展示了如何结合 `operator new` 和 `placement new` 来手动管理内存生命周期,这在高性能库开发中是常见做法。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值