关于placement new

本文详细解释了Placement New的概念及其用途,Placement New是一种特殊的operator new版本,用于在预先分配的内存中创建对象,从而提高程序效率。

何为placement new呢?placement new 是重载operator new的一个标准、全局的版本,它不能被自定义的版本代替(不像普通的operator new和operator delete能够被替换成用户自定义的版本)。

首先我们区分下几个容易混淆的关键词:new operator、operator new、placement new 。

对于new operator,其实它是语言内建的,我们是没有办法改变它的。当我们创建了一个new表达式时,会发生两件事。首先,使用operator new()分配内存,然后调用构造函数。现在明白了吧,new operator会去调用operator new()跟创建对象的构造函数,我们能控制的,只有内存的分配函数operator new()(对于operator delete()也是一样)。所谓控制,其实就是重载这个函数,编译器将用重载的operator new代替默认的版本去分配内存。

接下来就是要说的placement new了。其实它也是operator new重载的一个版本,只是很少人用到它。它有一个特点,就是允许你在已经分配好的内存上创建一个对象,也就是说,可以通过某种手段在指定的内存创建对象。

好了,说到这里,我们就可以利用它来做一些高效率的事情了。

当我们用new分配对象数组空间时,会自动调用对象的默认构造函数。可是如果数组只有一部分元素会被使用,或者元素立即被赋值,那刚刚自动调用对象的默认构造函数不就等于白做了吗?这时候placement new就发挥作用了,因为它可以在分配好的缓冲区上创建对象。采用这种方式,缓冲区占用的存储区的分配,可以避免被默认的构造函数初始化:

const size_t n = sizeof(string) * 30;

string *sbuf = static_cast<string *>(::operator new(n));/*这时候是直接调用operator new函数来分配内存的,也就是说,只会分配空间,类似于malloc。*/

下面是一个在分配好的内存空间上创建对象的函数:

void append(string buf[], int &size, const string &val)

{new (&buf[size++] string(val);}//palcement new

这样的话,我们就可以在需要的情况下使用pacement new通过复制构造函数来初始化数组里的元素,在一些情况下能够提高程序的效率。

但这样的话我们就得自己来负责清理工作了,凡事有利必有弊吧。

这里得通过显式调用string的析构函数,如:

buf[size].~string();

并用operator delete来释放存储区:

::operator delete(buf);

### `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` 来手动管理内存生命周期,这在高性能库开发中是常见做法。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值