关于C++中数组placement new用法正确性的技术问询
手动模拟new[]/delete[]的问题解答
一、数组placement new的用法是否正确?
你的代码核心逻辑是对的,但存在一处未定义行为:
- 直接对
void*类型的mem_ptr_arr执行指针加法mem_ptr_arr+sizeof(Point)*i不符合C++标准,因为void*没有明确的大小,编译器无法正确计算偏移量。 - 正确做法是先将
void*转换为char*(char大小固定为1字节,偏移计算完全确定),再进行内存偏移:char* char_mem = static_cast<char*>(mem_ptr_arr); for(int i=0; i<3; i++) new( char_mem + sizeof(Point)*i ) Point(i,i); - 其余流程完全正确:通过
operator new分配足够容纳3个Point的内存,循环调用placement new构造每个对象,手动逐个调用析构函数,最后用operator delete释放内存,这完全对应new[]/delete[]的底层执行逻辑(对于有自定义析构函数的类,delete[]会自动遍历调用析构,再释放内存)。
二、释放后未复用相同堆地址的原因
这是堆内存分配器的正常行为,不存在问题:
- 堆分配器没有强制复用刚释放内存块的义务,其分配策略受多种因素影响:当前内存碎片状态、分配器的缓存机制(比如线程本地缓存)、是否为减少碎片选择新内存页等。
- 你手动释放内存后立即调用
new Point[3]{};,分配器可能出于效率或内部管理需求,选择从其他区域分配内存,而非复用刚释放的块。 - 若想观察内存复用,可以尝试多次重复分配-释放循环,或调整分配的内存大小,某些场景下可能出现复用,但这不是必然结果。
修正后的测试代码
#include <vector> #include <iostream> class Point { int x,y; public: Point():x(0), y(0){std::cout<<"Point() : "<<this<<std::endl;} void print(){std::cout<<x<<":"<<y<<std::endl;} Point(int a, int b) :x(a), y(b){std::cout<<"Point(int,int) : value & addr "<<a<<":"<<b<<" ~ "<<this<<std::endl;} ~Point(){std::cout<<"~Point() : "<<this<<" "<<x<<":"<<y<<std::endl;} }; int main() { // multiple allocation void* mem_ptr_arr = operator new(sizeof(Point)*3); // 修正:先转char*再计算偏移 char* char_mem = static_cast<char*>(mem_ptr_arr); for(int i=0; i<3; i++) new( char_mem + sizeof(Point)*i ) Point(i,i); Point* ref_ptr_arr = static_cast<Point*>(mem_ptr_arr); // delete process for(int i=0; i<3; i++) (ref_ptr_arr+i)->~Point(); operator delete(ref_ptr_arr); Point* new_ptr = new Point[3]{}; delete[] new_ptr; return 0; }
内容的提问来源于stack exchange,提问作者ALPHA
相关产品推荐
相关产品推荐

