Reading a shader from a .txt file using a structure

你。 提交于 2019-12-02 01:29:10

You're using a mix of C++ (std::string) and C (char*) strings in an invalid way.

In the constructor, you're building up the code in a C++ string, which is an object that automatically allocates and re-allocates the memory to hold the string data as the string grows. It will also automatically free that data when it goes out of scope at the end of the constructor.

The root of the problem is here:

source = allLines.c_str();

where source is a class/struct member. The c_str() method on the string gives you a pointer to the internal string data of the object. As explained above, this data is freed when allLines goes out of scope at the end of the shaderReader constructor, so you end up with a pointer to freed memory. This results in undefined behavior, because this memory could now be used for something else.

The cleanest way to fix this is to use C++ strings consistently. Change the struct definition to:

struct shaderReader
{
    shaderReader::shaderReader(std::string);
    std::string source;
};

Then in the constructor, you can read the source code directly into this class member:

while (std::getline(theFile, line))
{
    source = source + line + "\n";
}

The only reason why you have to bother with a char* is because glShaderSource() needs one. The safest approach is to convert this at the last moment:

const GLchar* ob1 = vertexShader.source.c_str();
GLuint vertexShaderObject = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShaderObject, 1, &ob1, NULL);
glCompileShader(vertexShaderObject);

This way, you only use the pointer to the internal string data very temporarily, and you don't have to bother with C-style strings and memory management otherwise.

zwcloud

change

source = allLines.c_str();

into

source = new char[allLines.length()+1];
strcpy(source,allLines.c_str());

And in the destructor of shaderReader, release the memory allocated for source

if(source)
{
    delete[] source;
    source = nullptr;
}

Ref: https://stackoverflow.com/a/12862777/3427520

I would be tempted to store your shader in a std::vector<GLchar> so you don't need to worry about allocating and deallocating memory:

Maybe something like this:

struct shaderReader
{
    shaderReader(std::string);
    std::vector<GLchar> source;
    const GLchar* data;
    GLint size;
};

shaderReader::shaderReader(std::string name)
{
    std::string line, allLines;
    std::ifstream theFile(name);
    if(theFile.is_open())
    {
        while(std::getline(theFile, line))
        {
            allLines = allLines + line + "\n";
        }

        source.assign(allLines.begin(), allLines.end());
        size = source.size();
        data = source.data();

        theFile.close();
    }
    else
    {
        std::cout << "Unable to open file.";
    }
}

int main()
{
    shaderReader sr("fragment-shader.txt");
    GLuint shader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(shader, 1, &sr.data, &sr.size);
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!