从方法非确定性行为返回 std::字符串

Returning std::string from method non-deterministic behavior?

本文关键字:std 字符串 返回 性行为 方法 非确定      更新时间:2023-10-16

我有一个读取文件并将其内容作为std::string返回的方法。我使用返回的std::string来编译一个 OpenGL 程序。在某些情况下,链接失败(编译的顶点着色器已损坏),因为NULL了一个或两个着色器部分(读取文件内容)。

  • 如果我逐步调试我的代码,一切都很好。
  • 如果我打印文件内容,链接似乎失败的频率较低。

为什么它的行为不同,我的错误在哪里?

末尾的cout始终打印正确的文件内容:

std::string read_file(const char* filePath) {
    std::string content;
    std::ifstream stream(filePath, std::ios::in);
    if (stream.is_open()) {
        std::string line = "";
        while(getline(stream, line)) {
            content += "n" + line;
        }
    }
    std::cout << "read_file " << content << "end read_file" << std::endl; // always prints the correct content
    return content; // makes a copy, don't like that, unless RVO?..
}

fragmentSource和/或vertextSource有时为空:

    GLuint fragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
    GLuint vertexShaderID = glCreateShader(GL_VERTEX_SHADER);
    const char* fragmentSource = tools::read_file(_fragmentShaderPath).c_str();
    std::cout << "vertext shader source: " << std::endl << fragmentSource; // empty sometimes
    glShaderSource(fragmentShaderID, 1, &fragmentSource, NULL);
    glCompileShader(fragmentShaderID);
    CheckCompilation(fragmentShaderID);
    const char* vertexSource = tools::read_file(_vertexShaderPath).c_str();
    std::cout << "vertext shader source: " << std::endl << vertexSource; // empty sometimes
    glShaderSource(vertexShaderID, 1, &vertexSource, NULL);
    glCompileShader(vertexShaderID);
    CheckCompilation(vertexShaderID);
    GLuint programId = glCreateProgram();
    glAttachShader(programId, fragmentShaderID);
    glAttachShader(programId, vertexShaderID);
    glLinkProgram(programId);
    GLint result = GL_FALSE;
    GLint infoLogLength;
    glGetProgramiv(programId, GL_LINK_STATUS, &result);
    glGetProgramiv(programId, GL_INFO_LOG_LENGTH, &infoLogLength);
    if (infoLogLength > 0) { // this fails sometimes, corresponding to either vertexSource or fragmentSource being empty
        std::vector<char> infoLog(infoLogLength + 1);
        glGetProgramInfoLog(programId, infoLogLength, NULL, &infoLog[0]);
        std::cout << &infoLog[0] << std::endl;
    }

替换

const char* fragmentSource = tools::read_file(_fragmentShaderPath).c_str();

std::string fragmentSourceStr = tools::read_file(_fragmentShaderPath);
const char* fragmentSource = fragmentSourceStr.c_str();

vertexSource也是如此.

问题是您返回的字符串是临时字符串,因此在使用指向其数据的指针初始化fragmentSource后,它会被销毁,这使fragmentSource指向已销毁的存储。

如果是我,我宁愿只处理 c++ 类型,直到我们真正接触 openGL C api。

因此,首先我将在 tools 命名空间中创建一个轻量级代理函数:

namespace tools {
    auto shaderSource(GLuint shaderId, const std::string& source)
    {
        auto ptr = std::addressof(source[0]);
        return glShaderSource(shaderId, 1, std::addressof(ptr), nullptr);
    }
}

然后完全替换原始指针的使用:

auto fragmentSource = tools::read_file(_fragmentShaderPath);
std::cout << "vertext shader source: " << std::endl << fragmentSource; // empty sometimes
tools::shaderSource(fragmentShaderID, fragmentSource);