C++遍历自定义List类存储的Chunk对象时程序崩溃该如何解决
崩溃原因
- 自定义
List类的At方法设计错误:当前At按值返回T而非引用,每次调用chunks.At(i)都会生成一个Chunk临时副本。而Chunk包含List<Block>类型的成员,List没有自定义拷贝构造函数,默认生成的拷贝构造只会做浅拷贝,导致临时副本的blocks和原Chunk的blocks共享同一块堆内存,访问时极易出现未定义行为。这也解释了你直接声明单个Chunk对象可以正常运行的原因:这种场景下没有发生Chunk的拷贝,不存在浅拷贝带来的内存问题。 List类完全没有实现拷贝控制(拷贝构造、拷贝赋值、析构函数),违反C++的三五法则,当List对象被拷贝、销毁时会出现野指针、重复释放等内存问题。- 额外的风险点:
At方法在索引越界时没有任何返回值,属于典型的未定义行为;如果内存被破坏导致blocks.size被读取为一个极大的错误值,会让内层循环次数暴增,占满CPU甚至触发系统内存保护,最终导致整机卡死。
解决方法
有两种可行方案:
方案1:修复自定义List类
- 修改
At方法返回引用,减少不必要拷贝同时避免浅拷贝问题,同时补充越界处理:
T& At(int index) { if (index < 0 || index >= size) { throw std::out_of_range("List index out of range"); } return ptr[index]; } // 补充const版本用于const对象访问 const T& At(int index) const { if (index < 0 || index >= size) { throw std::out_of_range("List index out of range"); } return ptr[index]; }
- 补充拷贝控制函数,避免浅拷贝:
// 析构函数 ~List() { delete[] ptr; } // 拷贝构造 List(const List<T>& other) { size = other.size; ptr = new T[65536]; for (int i = 0; i < size; i++) { ptr[i] = other.ptr[i]; } } // 拷贝赋值运算符 List<T>& operator=(const List<T>& other) { if (this != &other) { delete[] ptr; size = other.size; ptr = new T[65536]; for (int i = 0; i < size; i++) { ptr[i] = other.ptr[i]; } } return *this; }
- 修改
Add方法参数为常量引用,减少不必要的临时对象拷贝:
void Add(const T& a) { ptr[size] = a; size++; }
方案2:直接替换为std::vector(更推荐)
自定义容器很容易出现内存管理错误,直接用标准库的std::vector可以规避所有以上问题,替换逻辑如下:
- 把所有
List<T>替换为std::vector<T> - 把
Add方法调用替换为push_back/emplace_back - 把
At(index)调用替换为operator[](index)(无越界检查,性能更高)或者at(index)(有越界检查,调试更方便)
替换后你的主循环代码可以改为:
std::vector<Chunk> chunks; chunks.emplace_back(4, glm::vec3(0.0f)); // emplace_back直接构造,避免额外拷贝 while (!glfwWindowShouldClose(display.window)) { renderer.Prepare(); for (int i = 0; i < chunks.size(); i++) { for (int j = 0; j < chunks[i].blocks.size(); j++) { renderer.Render(chunks[i].blocks[j]); } } renderer.Clear(); }
内容的提问来源于stack exchange,提问作者user15918026
相关产品推荐
相关产品推荐

