简体   繁体   中英

Unexpected ifstream behavior?

I am trying to load GLSL vertex/fragment shader sources into const char* array to be used with OpenGL. The function I am using to do that is

const char* loadSource(const char* path)
{
   string line;
   stringstream output;
   ifstream source(path);

   if(source.is_open())
   {
       while(source.good())
       { 
           getline(source, line);
           output << line << endl;
       }
       source.close();
   }

   return output.str().c_str();
}

The source input works fine on first call. However if I call for the second source, the first source gets "corrupted" (both calls are inside scope of a single function):

const char* vs_source = loadSource("vertex.vert");  // vs_source loads fine
const char* fs_source = loadSource("fragment.frag"); // fs_source loads fine. vs_source is terminated sooner than after previous call.

Note: I tried to code vs_source directly into *.cpp file and both shaders compiled. This points out to the fact that I must be doing something silly in the loadSource function.

Question: What causes such weird behaviour of the text input?

When you return the result from your function, you create a dangling reference:

return output.str().c_str();

At the end of the expression the temporary std::string obtained from the stream is destroyed and the memory returned become invalid: any access to the array result in undefined bahvior.

BTW, this approach to input is wrong:

while(source.good())
{ 
    getline(source, line);
    output << line << endl;
}

You always need to check that the read was successful after reading:

while (std::getline(source, line)) {
    output << line << '\n';
}

Also, don't use std::endl . If you really mean to flush the stream use std::flush . Finally, you can get the same effect a lot easier and probably faster:

out << source.rdbuf();

... and, of course, out should be declared as std::ostringstream (not the extra o ).

What causes such weird behaviour of the text input?

return output.str().c_str();

returns a pointer which points to a local variable, when function loadSource returns output goes out of scope vs_source/fs_source are dangling pointers. Access to vs_source/fs_source have undefined behavior.

To fix your issue, you could return std::string instead:

std::string loadSource(const char* path)
{
    //...
    return output.str();
}

std::string vs_source = loadSource("vertex.vert");  // vs_source loads fine
std::string fs_source = loadSource("fragment.frag"); 

Why does everyone insist on doing this line-by-line reading of files? Just load the whole file at once . It's really simple:

std::string LoadFile(const std::string &filename)
{
    std::ifstream file (filename.c_str());
    if (file) {
        std::ostringstream os;
        os << file.rdbuf();
        return os.str();
    }
    else {
        // error
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM