delete[]是否依赖指针原始指向?下述代码是否合法或存在内存泄漏?
关于delete[]如何知晓数组大小及指针移动后的delete[]有效性问题
一、delete[]是怎么知道要操作的数组大小的?
先从底层内存分配的逻辑说起:
- 对于
malloc和free:malloc在分配内存时,会在内存块的隐藏头部区域记录这块内存的总大小,free就是靠读取这个值来确定要释放的内存范围。 - 而
new[]和delete[]的机制更特殊:它们底层确实依赖malloc/free,但new[]会额外在内存块中单独存储创建的元素数量(这个信息和malloc记录的总内存大小是分开的)。当调用delete[]时,它会先读取这个元素计数:- 如果元素类型有自定义析构函数,就按照计数调用对应次数的析构函数;
- 最后再调用
free释放整个内存块。
二、你的代码是否合法?会导致内存泄漏吗?
先看你提供的代码:
void createArray(){ char* someArray = new char[20]; readData(someArray); //指针移动一位后,此delete是否仍有效? delete[] someArray; } char readData(char* &arr){ char value = *arr; //让指针指向下一个元素 arr += 1; return value; }
结论很明确:这段代码属于未定义行为,存在严重风险,绝对不能这么写!
关键原因在于:delete[]有严格的要求——传入的指针必须是**new[]返回的原始起始指针**(或者nullptr)。你的代码里,readData通过引用修改了someArray,让它指向数组的第二个元素,此时传给delete[]的已经不是最初分配的内存起始地址了。
可能你会发现某些环境下这么写程序没崩溃,这是因为char是内置类型,没有析构函数,此时delete[]的行为近似于free。但即使是free,C标准也明确要求传入的指针必须是malloc(或同类分配函数)返回的原始指针,把指向内存块中间的指针传给free同样是未定义行为——它可能在某些系统下“看似正常”,但也可能造成堆损坏、内存泄漏甚至程序崩溃。
正确的做法是始终保留new[]返回的原始指针,用它来调用delete[]。比如可以修改代码,用一个临时指针来遍历数组,不改动原始指针:
void createArray(){ char* someArray = new char[20]; char* currentPtr = someArray; readData(currentPtr); delete[] someArray; // 用原始指针释放,安全合法 } char readData(char* &arr){ char value = *arr; arr += 1; return value; }
内容的提问来源于stack exchange,提问作者Kilian
相关产品推荐
相关产品推荐

