C++读取文件有时返回空字符串的OpenGL着色器加载问题
搞定这个“薛定谔”的着色器读取问题!
嘿,这个“有时正常有时读空”的问题我之前也踩过坑!本质根本不是什么异步延迟,而是悬空指针引发的未定义行为——简单说就是你拿到的指针指向了已经被销毁的内存,运气好的时候内存还没被覆盖就正常,运气差的时候就读空了。
问题到底出在哪?
咱们拆解一下你的代码逻辑:
parseShader()返回的是一个临时的std::string对象,这个对象只在当前代码行的生命周期内存在- 当你写
parseShader("xxx.glsl").c_str()时,c_str()返回的指针确实指向了字符串的内容,但这行代码执行完,临时字符串就被销毁了,内存也被释放 - 你把这个指针存在
vertex_shader_text里,后续调用strlen()或者glShaderSource()时,这个指针已经变成“悬空”的了——指向的内存可能已经被其他数据覆盖,也可能还没,这就导致了时好时坏的现象
怎么解决?很简单:延长字符串的生命周期
你只需要把 parseShader 返回的字符串保存到一个持久的变量里,让它的生命周期覆盖到你使用指针的整个过程就行。修改后的代码如下:
// 先把着色器内容存到持久变量里,别用临时对象! std::string vertex_shader_content = parseShader("res/shaders/basic.vertex.glsl"); const char* vertex_shader_text = vertex_shader_content.c_str(); std::cout << "Vertex shader length is " << strlen(vertex_shader_text) << std::endl; glShaderSource(vertex_shader, 1, &vertex_shader_text, NULL); glCompileShader(vertex_shader); std::string fragment_shader_content = parseShader("res/shaders/basic.fragment.glsl"); const char* fragment_shader_text = fragment_shader_content.c_str(); std::cout << "Fragment shader length is " << strlen(fragment_shader_text) << std::endl; glShaderSource(fragment_shader, 1, &fragment_shader_text, NULL); glCompileShader(fragment_shader);
额外加分:给读取函数加错误检查
另外你的 parseShader 函数没有任何错误处理,如果文件路径错了、文件不存在,也会返回空字符串。建议加上错误提示,方便排查问题:
static const std::string parseShader(const std::string &fileName){ std::ifstream ifs(fileName); // 检查文件是否成功打开 if (!ifs.is_open()) { std::cerr << "Error: 打不开着色器文件 -> " << fileName << std::endl; return ""; } std::stringstream buffer; buffer << ifs.rdbuf(); return buffer.str(); }
这样以后如果再遇到读空的情况,你就能立刻知道是文件没找到,而不是一脸懵啦~
内容的提问来源于stack exchange,提问作者Killrazor
相关产品推荐
相关产品推荐

