我有一个相当简单的log()
方法用于GL着色器和程序便利类,因为相应的compile
和link
方法只返回bool
,同时隐藏所有GL呼叫;如,
std::string
glShader::log () const
{
std::string info;
GLint len = 0;
if (!glIsShader(gl_shader_obj))
info = "(invalid shader object)\n";
else
glGetShaderiv(gl_shader_obj, GL_INFO_LOG_LENGTH, & len);
if (len != 0)
{
info.resize(static_cast<std::string::size_type>(len));
glGetShaderInfoLog(gl_shader_obj, len, NULL, & info[0]);
}
return info;
}
这是对std::string::resize (size_type)
参数的误用吗?我知道C ++ 11在查询时要求一个空终止字符,即c_str()
;但它是否保证其存在?这可能是实现string
以简化C字符串访问的“合理”方式,但不是必需的。
但是,如果有日志,GL_INFO_LOG_LENGTH
包含日志中字符数的\0
;否则日志长度只是零。
我是否可能以这种方式写出string
保留缓冲区的末尾?我应该在(len - 1)
电话中使用InfoLog
吗?或者我对C ++ 11字符串的想法有误吗?也就是说,我可以使用null终止符安全地覆盖吗?
答案 0 :(得分:3)
是的,这是对std::string
的有效使用。您可以获得指向第一个字符的指针并写入字符数组,只要您不超出范围[0,size()
)。
然而,你确实犯了一个错误。请参阅GL_INFO_LOG_LENGTH
在长度中包含NUL终止符。这意味着,从技术上讲,您的std::string
比其需要的字符长一个字符。 info
的最后一个字符将是一个NUL字符,而std::string
会将它视为字符串数据的一部分,而不是标记字符串结尾的分隔符。< / p>
您应该不尝试通过在设置len
的尺寸之前从info
中减去1来解决此问题。为什么?因为glGetShaderInfoLog
将总是 NUL终止它写入的字符串。因此,如果缩小len
,它将从日志中删除最后一个实际字符。
相反,您应该在从OpenGL复制后缩小info
:
info.resize(static_cast<std::string::size_type>(len));
glGetShaderInfoLog(gl_shader_obj, len, NULL, & info[0]);
info.pop_back();
在C ++ 17中,标准写法已经改为允许写入字符串的NUL终结符,只要你用NUL字符覆盖它。它还允许string::data
返回非const
字符数组。因此,现在可以正常工作:
info.resize(static_cast<std::string::size_type>(len - 1));
glGetShaderInfoLog(gl_shader_obj, len, NULL, info.data());
标准要求info
的大小为+ 1个字节。