存储于std::map中的Shader获取失败问题排查求助
问题分析与解决方案
核心问题:默认拷贝语义导致OpenGL程序对象被提前销毁
你的Shader类未处理拷贝构造与拷贝赋值逻辑,而std::map存储的是对象值,以下操作触发了致命的默认拷贝行为:
AddShader中临时对象shader赋值给Shaders[name]时,默认赋值仅拷贝m_RendererID数值,导致两个对象共享同一个OpenGL程序ID。AddShader函数结束后,临时对象shader销毁,其析构函数调用glDeleteProgram(m_RendererID),直接删除了OpenGL中的程序对象。此时std::map内的Shader对象持有的m_RendererID已变为无效值。- 调用
GetShader时,不仅检查的是无效ID,且返回值为Shader对象(而非引用),会再次触发拷贝,返回的临时对象销毁时还会重复删除同一个无效ID,进一步加剧问题。
具体修复步骤
1. 禁用Shader类的拷贝语义
在Shader.h的类声明中,显式删除拷贝构造与拷贝赋值运算符,杜绝意外拷贝:
class Shader { // ... 原有私有成员 ... public: // 禁用拷贝操作 Shader(const Shader&) = delete; Shader& operator=(const Shader&) = delete; // ... 原有构造/析构/成员函数 ... };
2. 修改std::map存储智能指针
将std::map<std::string, Shader>改为存储std::unique_ptr<Shader>,避免对象拷贝:
#include <memory> std::map<std::string, std::unique_ptr<Shader>> Shaders;
3. 调整AddShader函数逻辑
使用智能指针创建Shader对象,直接移入map:
void AddShader(std::string filepath, std::string name) { auto shader = std::make_unique<Shader>(filepath); if (glIsProgram(shader->m_RendererID) != GL_TRUE) { std::cout << "invalid program" << std::endl; __debugbreak(); } Shaders[name] = std::move(shader); }
4. 修改GetShader返回引用
返回Shader&避免拷贝,同时确保访问的是map内的有效对象:
Shader& GetShader(std::string name) { auto& shaderPtr = Shaders[name]; if (glIsProgram(shaderPtr->m_RendererID) != GL_TRUE) { std::cout << "invalid program" << std::endl; __debugbreak(); } return *shaderPtr; }
5. 主函数中调整调用方式
因为返回的是引用,直接绑定使用即可:
Shader& shader = GetShader("shader1"); Shader& shader2 = GetShader("shader2"); shader.Bind();
额外优化建议
- 将
m_RendererID设为私有成员,提供GetRendererID()公共方法封装访问。 - 在
CreateShader中添加glLinkProgram结果检查,避免生成无效程序对象。
内容的提问来源于stack exchange,提问作者jumpjet080
相关产品推荐
相关产品推荐

