自定义C++模板Array类malloc报错排查:小容量数组触发异常
自定义模板Array类的内存问题解析
问题代码
Array类实现
template<typename T> class Array{ public: Array(size_t size) : array_size(size){ this->m_Data = (T*)malloc(sizeof(T) * size); } void insert(size_t index, T value){ size_t temp_size = this->array_size + 1; T *temp = (T*)malloc(sizeof(T) * temp_size ); //memcpy(temp, this->m_Data, this->array_size ); for(size_t l = 0; l < temp_size; l++ ) temp[l] = this->m_Data[l]; for(size_t i = temp_size; i >= index; i--){ temp[i] = temp[(i-1)]; } temp[index - 1] = value; free(this->m_Data); this->m_Data = NULL; this->m_Data = temp; this->array_size = temp_size; //free(temp); //delete(temp); } void append(T value){ size_t temp_size = this->array_size + 1; std::cout << "temp_size: " << temp_size << std::endl; std::cout << "sizeof(T): " << sizeof(T) << std::endl; // returns 4 std::cout << "temp_size * sizeof(T): " << (temp_size * sizeof(T)) << std::endl; // returns 44 T *temp = (T*)malloc((temp_size * sizeof(T))); // error! } private: size_t array_size; T *m_Data; };
测试代码
int main(int argc, char *argv[]) { Array<int> data(9); data.insert(1, 100); // seams to work fine data.append(100000); }
问题原因分析
1. insert函数中调用free(temp)导致乱码的原因
temp是你新分配的内存块,最后你把this->m_Data指向了temp,这块内存已经成为Array类的有效数据存储区。如果调用free(temp),会直接释放这块内存,此时m_Data变成野指针,后续访问数组元素时读取的是已释放的无效内存,自然会出现乱码。这里绝对不能free temp,因为它已经是数组的新数据容器。
2. append函数malloc出错的根源:insert中的内存越界破坏了堆
append的malloc写法本身没问题,但insert函数里的两处内存越界操作已经破坏了堆内存结构,导致后续malloc调用失败:
- 第一个循环越界:
for(size_t l = 0; l < temp_size; l++ ) temp[l] = this->m_Data[l];temp_size是原数组大小+1,而this->m_Data只有array_size个元素,当l >= array_size时,m_Data[l]属于越界访问,会读写不属于数组的内存区域,破坏堆的元数据。 - 第二个循环越界+无符号类型溢出:
for(size_t i = temp_size; i >= index; i--){ temp[i] = temp[(i-1)]; }temp的有效索引范围是0 ~ temp_size-1,初始i = temp_size直接访问temp[temp_size]属于越界写入,破坏堆结构。size_t是无符号整数类型,当i减到0时,i--会变成SIZE_MAX(无符号整数溢出),导致循环无法终止,进一步疯狂破坏内存。
另外,insert中temp[index - 1] = value的写法存在风险:如果用户传入index=0,index-1会变成SIZE_MAX,再次触发越界。
修复建议
- 替换malloc/free为new/delete:C模板类应优先使用C内存管理方式,对于非POD类型,malloc不会调用构造函数,会导致对象未初始化。
- 修正insert的循环逻辑:
- 拷贝原数组元素时,循环上限改为
array_size,而非temp_size。 - 元素后移的循环从
temp_size-1开始,到index结束(建议统一使用0-based索引,避免混淆)。 - 对传入的index做合法性检查,避免越界访问。
- 拷贝原数组元素时,循环上限改为
内容的提问来源于stack exchange,提问作者NaturalDemon
相关产品推荐
相关产品推荐

