自定义模板Vector类释放不定大小数组指针触发SIGABRT错误求助
分析Vector类析构时SIGABRT错误的原因与解决方案
让我来帮你拆解这个问题——你的Vector类在析构时触发SIGABRT,核心问题出在指针数组的内存管理上,咱们一步步看:
错误原因分析
先看你的构造函数里的关键代码:
T** p = new T*; // 只分配了单个T*指针的内存空间 Vector(int chunkSize = 1000) { this->chunkSize = chunkSize; p[0] = new T[chunkSize]; }
这里的p本质是一个指向单个指针的指针,并不是可扩展的指针数组。但在pushBack方法中,你通过pos / chunkSize计算chunk索引,当pos >= chunkSize时(比如pos=1000,索引为1),访问p[1]就属于越界访问非法内存了。
这些越界写入的指针值是随机无效的,等到析构函数里尝试delete[] p[i]时,你其实是在delete一个完全无效的内存地址,直接触发了操作系统的SIGABRT信号(检测到非法内存操作)。另外,原代码还漏掉了释放p本身的内存,这也会导致内存泄漏。
解决方案
要解决问题,你需要让p成为可动态扩展的指针数组,这里有两种靠谱的实现方式:
方式一:用std::vector管理chunk指针(推荐)
直接用标准库的std::vector<T*>来替代T** p,让标准库帮你处理扩容和内存管理,代码更简洁安全:
#include <vector> #include <iostream> template <class T> class Vector { int pos = 0; int chunkSize; std::vector<T*> chunks; public: Vector(int chunkSize = 1000) : chunkSize(chunkSize) { chunks.push_back(new T[chunkSize]); std::cout << chunks[0] << std::endl; } ~Vector() { for (auto chunk : chunks) { std::cout << chunk << std::endl; delete[] chunk; } } void pushBack(T val) { int chunkIdx = pos / chunkSize; int elemIdx = pos % chunkSize; // 当需要新chunk时,自动扩容 if (chunkIdx >= chunks.size()) { chunks.push_back(new T[chunkSize]); } chunks[chunkIdx][elemIdx] = val; pos++; } void display() { for (int i = 0; i < pos; i++) { int chunkIdx = i / chunkSize; int elemIdx = i % chunkSize; std::cout << chunks[chunkIdx][elemIdx] << " "; } std::cout << std::endl; } };
方式二:手动实现指针数组扩容(适合学习)
如果想自己实现扩容逻辑,可以保留T** p,但需要维护指针数组的容量,当需要扩容时重新分配更大的空间:
#include <iostream> template <class T> class Vector { int pos = 0; int chunkSize; int pCapacity = 1; T** p = new T*[pCapacity]; public: Vector(int chunkSize = 1000) : chunkSize(chunkSize) { p[0] = new T[chunkSize]; std::cout << p[0] << std::endl; } ~Vector() { // 释放所有chunk int totalChunks = pos / chunkSize + (pos % chunkSize != 0 ? 1 : 0); for (int i = 0; i < totalChunks; i++) { std::cout << p[i] << std::endl; delete[] p[i]; } delete[] p; // 别忘了释放指针数组本身 } void pushBack(T val) { int chunkIdx = pos / chunkSize; int elemIdx = pos % chunkSize; // 指针数组容量不足时扩容 if (chunkIdx >= pCapacity) { int newCapacity = pCapacity * 2; T** newP = new T*[newCapacity]; // 拷贝旧指针到新数组 for (int i = 0; i < pCapacity; i++) { newP[i] = p[i]; } delete[] p; p = newP; pCapacity = newCapacity; } // 新chunk需要分配内存 if (elemIdx == 0 && chunkIdx > 0) { p[chunkIdx] = new T[chunkSize]; } p[chunkIdx][elemIdx] = val; pos++; } void display() { for (int i = 0; i < pos; i++) { int chunkIdx = i / chunkSize; int elemIdx = i % chunkSize; std::cout << p[chunkIdx][elemIdx] << " "; } std::cout << std::endl; } };
额外注意点
- 如果需要Vector支持拷贝或赋值,还要实现拷贝构造函数和赋值运算符(遵循Rule of Three),避免浅拷贝导致的重复delete问题。
- 可以用Valgrind工具检查内存泄漏,确保所有分配的内存都被正确释放。
内容的提问来源于stack exchange,提问作者nanoandrew4
相关产品推荐
相关产品推荐

