将自定义Drawable存入容器后绘制触发段错误的技术求助
段错误原因分析及解决办法
看起来你在绘制按钮时遇到了段错误,结合你的代码,我帮你梳理几个最可能的原因和对应的解决思路:
1. Button类的拷贝构造问题(最常见)
你在循环中创建Button局部实例,然后用push_back把它拷贝到levelButtons容器里。如果Button类内部持有裸指针(比如你传入的&levelTexture),而没有实现正确的拷贝构造函数和赋值运算符,就会触发浅拷贝:多个Button实例会共享同一个levelTexture指针。一旦原levelTexture的生命周期结束(比如它是局部变量,循环结束后被销毁),或者某个实例意外释放了这个指针,后续绘制时访问这个野指针就会直接触发段错误。
解决办法:
- 方案一:实现深拷贝的拷贝构造
给Button类手动实现拷贝构造函数和赋值运算符,确保对于levelTexture这类资源,要么创建新的副本(比如调用SDL的纹理复制接口),要么用引用计数来管理资源(比如把levelTexture换成std::shared_ptr<SDL_Texture>)。 - 方案二:避免拷贝,存储指针
把levelButtons改成std::vector<std::unique_ptr<Button>>,这样直接存储按钮的指针,不会触发拷贝:// 修改容器定义 std::vector<std::unique_ptr<Button>> levelButtons; // 循环内创建并添加 for (int i = 1; i <= 8; i++) { for (int j = 0; j < 4; j++) { auto btn = std::make_unique<Button>(50, 50, std::bind(&Game::continueGame, this, (j * 8) + i), " " + std::to_string((j * 8) + i), &levelTexture); btn->setPosition(50 + (i * 100), 200 + (j * 100)); levelButtons.push_back(std::move(btn)); } } // 绘制时 for (auto& btn : levelButtons) { win->draw(*btn); }
2. win指针失效
如果在执行绘制代码时,win这个窗口指针已经变成了野指针(比如窗口被提前销毁、win指向的内存被释放但没有置空),调用win->draw()就会直接触发段错误。
解决办法:
- 在绘制前检查
win的有效性,比如添加断言:assert(win != nullptr && "Window pointer is invalid!"); - 排查代码中是否有提前销毁窗口或者重置
win指针的逻辑,确保绘制时win指向有效的窗口对象。
3. levelTexture的生命周期问题
如果levelTexture是局部变量(比如在某个函数内定义,函数结束后就被销毁),那么你传给Button的&levelTexture就会变成野指针。当绘制按钮时,Button尝试访问这个已经被释放的纹理资源,就会触发段错误。
解决办法:
- 确保
levelTexture的生命周期至少和levelButtons一样长,比如把它改成Game类的成员变量,而不是局部变量。 - 或者用智能指针管理纹理,比如
std::shared_ptr<SDL_Texture>,这样即使原变量销毁,只要有Button实例持有这个智能指针,纹理资源就不会被释放。
内容的提问来源于stack exchange,提问作者MBJH
相关产品推荐
相关产品推荐

