出乎意料的ifstream行为?

时间:2013-08-25 01:35:30

标签: c++

我正在尝试将GLSL顶点/片段着色器源加载到const char *数组中以与OpenGL一起使用。我用来做的功能是

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();
}

源输入在第一次调用时工作正常。但是,如果我调用第二个源,则第一个源被“损坏”(两个调用都在单个函数的范围内):

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.

注意:我尝试将vs_source直接编码为* .cpp文件并编译了两个着色器。这指出了我必须在loadSource函数中做一些愚蠢的事情。

问题:导致文本输入出现这种奇怪行为的原因是什么?

3 个答案:

答案 0 :(得分:3)

当您从函数返回结果时,您将创建一个悬空参考:

return output.str().c_str();

在表达式结束时,从流中获取的临时std::string将被销毁,并且返回的内存将变为无效:对数组的任何访问都会导致未定义的bhavior。

顺便说一句,这种输入方法是错误的:

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

始终需要检查读取是否成功 阅读后

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

另外,请勿使用std::endl。如果你真的想要刷新流,请使用std::flush。最后,您可以更轻松,更快地获得相同的效果:

out << source.rdbuf();

...当然,out应声明为std::ostringstream(不是额外的o)。

答案 1 :(得分:1)

  

导致文本输入出现这种奇怪行为的原因是什么?

return output.str().c_str();

返回一个指向局部变量的指针,当函数loadSource返回output超出范围vs_source/fs_source时,是悬空指针。对vs_source/fs_source的访问具有未定义的行为。

要解决您的问题,您可以改为返回std :: string:

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"); 

答案 2 :(得分:1)

为什么每个人都坚持要逐行阅读文件?只需load the whole file at once。这很简单:

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
    }
}