为什么我通过流获取的std::string被覆盖了?

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

假设我有这样一个函数:

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

然后是这样的代码:

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

我不明白为什么 vertex_shader_source 最终会被对 get_shader 的后续调用覆盖。我该如何解决这个问题?

对于语句,

const GLchar * vertex_shader_source = get_shader("triangle_vertex.vs").c_str();
// The temporary `std::string` will be destroyed here.

get_shader returns 一个临时的 std::string,它会在声明后被销毁,这意味着 vertex_shader_source 将持有一个无效的指针,解引用它会导致UB.

你看到的可能是deallocated后内存重用导致的,但是UB就是UB,一切皆有可能。

您可以为其定义一个命名变量,例如:

std::string vertex_shader_source_string = get_shader("triangle_vertex.vs");
const GLchar * vertex_shader_source = vertex_shader_source_string.c_str();
const GLchar * vertex_shader_source = get_shader("triangle_vertex.vs").c_str();

vertex_shader_source 绑定到 "inside" 从 get_shader 返回的临时值 std::string。这根本不是 "extend" 临时文件的生命周期。一旦该语句的执行完成并继续,该临时内存(以及您现在持有的指针)将无法再以定义的方式访问。

本质上你是在调用未定义的行为。

vertex_shader_source 更合适的声明可以是 std::string。由于该值是从函数返回的,因此它是一个右值,将调用适当的移动构造。

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

如果此时您仍然 const GLchar*vertex_shader_source.c_str() 就可以了。