You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

关于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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 07:40:38