You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

存储于std::map中的Shader获取失败问题排查求助

问题分析与解决方案

核心问题:默认拷贝语义导致OpenGL程序对象被提前销毁

你的Shader类未处理拷贝构造与拷贝赋值逻辑,而std::map存储的是对象值,以下操作触发了致命的默认拷贝行为:

  1. AddShader中临时对象shader赋值给Shaders[name]时,默认赋值仅拷贝m_RendererID数值,导致两个对象共享同一个OpenGL程序ID。
  2. AddShader函数结束后,临时对象shader销毁,其析构函数调用glDeleteProgram(m_RendererID),直接删除了OpenGL中的程序对象。此时std::map内的Shader对象持有的m_RendererID已变为无效值。
  3. 调用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 12:54:18