Search code examples
c++ifstreamstdstringc-stringsostringstream

Why is my std::string obtained via stream being overwritten?


Assume I have a function like so:

std::string get_shader(std::string path) {
     std::string fullpath = "./resources/shaders/" + path;
     std::ifstream vertexShaderFile(fullpath);
     std::ostringstream vertexBuffer;
     vertexBuffer << vertexShaderFile.rdbuf();
     return vertexBuffer.str();
}

And then some code like this:

GLuint vertex_shader;
GLuint fragment_shader;
GLuint program;

const GLchar * vertex_shader_source = get_shader("triangle_vertex.vs").c_str();

// At this point vertex_shader_source is correct.

const GLchar * fragment_shader_source = get_shader("fragment.vs").c_str();

// Now vertex_shader_source is the same as fragment_shader_source

I don't understand why vertex_shader_source ends up being overwitten by a subsequent call to get_shader. How do I fix this?


Solution

  • const GLchar * vertex_shader_source = get_shader("triangle_vertex.vs").c_str();
    

    The vertex_shader_source is bound to a value "inside" the temporary std::string returned from get_shader. This does not "extend" the lifetime of the temporary at all. Once the execution of that statement is complete and continues, that temporary, and it's memory (and the pointer you now hold) is no longer accessible in a defined manner.

    Essentially you are invoking undefined behaviour.

    A more appropriate declaration of the vertex_shader_source could be as a std::string. Since the value is being returned from the function, it is a rvalue and the appropriate move construction will be invoked.

    std::string vertex_shader_source = get_shader("triangle_vertex.vs");
    

    If you still the the const GLchar* at this point, vertex_shader_source.c_str() will do.