placement new
和普通的 new
运算符的一个关键区别就在于内存分配和对象构造是分开的,这也是为什么你需要分别处理内存释放和对象析构。
普通的 new
和 delete
- 普通的
new
:在普通的new
操作中,内存分配和对象构造是同时进行的。当你写T* obj = new T(args...);
时,系统会首先为对象分配足够的内存,然后调用对象的构造函数在这块内存上构造对象。 - 普通的
delete
:当你调用delete obj;
时,系统会自动做两件事:首先调用对象的析构函数,然后释放内存。这两步是紧密结合的,确保了对象的生命周期和内存管理都是自动化的。
placement new
-
placement new
:在placement new
的操作中,内存分配和对象构造是分开的。你手动分配一块内存,然后使用placement new
在这块内存上构造对象。这种分离给你带来了更大的灵活性,但也意味着你必须手动管理对象的生命周期和内存的释放。 -
void*指针: placement new需要void*的指针来指明构造对象的地址位置。
-
例如:
void* memory = operator new(sizeof(MyClass)); // 手动分配内存 注意 operator new和new的区别 //void* memory = malloc(sizeof(MyClass)); MyClass* obj = new(memory) MyClass(42); // 在分配的内存上构造对象
这里
memory
是你手动分配的内存,而对象obj
是在这块内存上构造的。 -
手动析构和释放内存:
- 析构对象:你需要在合适的时机手动调用析构函数来销毁对象。例如,
obj->~MyClass();
会调用对象的析构函数,但这不会释放内存。 - 释放内存:你还需要手动释放之前分配的内存。例如,
operator delete(memory);
会释放内存。这与普通的delete
不同,因为delete
会自动调用析构函数和释放内存,而在使用placement new
时,这两个步骤是分开的。
- 析构对象:你需要在合适的时机手动调用析构函数来销毁对象。例如,
总结
因为 placement new
分离了内存分配和对象构造,你必须手动管理这两个过程。构造对象后,必须手动调用析构函数来销毁对象,然后手动释放内存。普通的 new
和 delete
是一气呵成的,placement new
则要求你分开进行这两步操作。