2016-02-16 13 views
1

Предположим, у меня есть функция, например, так:Почему моя std :: string получается через поток, который перезаписывается?

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 заканчивает тем, что overwitten последующим обращением к get_shader. Как это исправить?

ответ

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

vertex_shader_source связан со значением «внутри» временный std::string вернулся из get_shader. Это вовсе не «продлевает» время жизни. Как только выполнение этого утверждения завершено и продолжается, это временное и его память (и текущий указатель) больше не доступны определенным образом.

По сути, вы вызываете неопределенное поведение.

Более подходящее объявление vertex_shader_source может быть как std::string. Поскольку значение возвращается из функции, это значение rvalue, и соответствующая конструкция перемещения будет вызвана.

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

Если вы до сих пор const GLchar* на данный момент, vertex_shader_source.c_str() будет делать.

+0

Просто пытаюсь понять: я думал, что get_shader() вернет копию строки, так что бы указатель на c_str() был действителен в пределах остальной части области? – Knox

+3

Да, он возвращает копию. Эта копия является временной. Когда вы вызываете функцию 'c_str()', вы получаете указатель на внутреннюю строку «c» временной 'std :: string'. После временного уничтожения этот указатель перестает быть действительным, и попытка доступа к нему не будет работать так, как вы хотите. – Niall

+0

А я думал, что вызов get_shader() будет эквивалентен созданию 'std :: string' в текущей области, но теперь я вижу, что он доживает до конца вызывающего его оператора. Благодарю. – Knox

1

Для утверждения,

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

get_shader возвращает временный std::string, который будет уничтожен после того, как заявление, это означает, что vertex_shader_source проведет недопустимый указатель, разыменование это приведет к UB.

То, что вы видели, может быть вызвано повторным использованием памяти после освобождения, но UB является UB, все возможно.

Вы можете определить именованный переменную для него, например:

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