#c #memory-management #opengl-es #android-ndk #new-operator
#c #управление памятью #opengl-es #android-ndk #new-оператор
Вопрос:
я пытаюсь найти причину следующего сбоя, о котором сообщается на Android:
сбой при (operator new(unsigned int) 22)
означает ли это, что память не была выделена успешно? и если это так, добавление std::nothrow и проверки null и выход из программы — правильное решение?
есть ли способ, которым я могу ограничить программу, чтобы она не выделялась, чтобы воспроизвести ее?
код, в котором происходит сбой :
glCompileShader( VSID );
GLint vstat;
glGetShaderiv( VSID, GL_COMPILE_STATUS, amp;vstat );
if( vstat != GL_TRUE )
{
GLint infolen;
glGetShaderiv( VSID, GL_INFO_LOG_LENGTH, amp;infolen );
GLchar* infostring = new GLchar[infolen 1];
glGetShaderInfoLog( VSID, infolen, nullptr, infostring );
infostring[infolen] = 0;
std::stringstream Error;
Error << "An Error occured while trying to compile"
" Vertex Shader "" << VertexShaderPath
<< "":nn" << infostring;
}
Комментарии:
1. Я полагаю, это
new GLchar[infolen 1];
сбой? Каково значениеinfolen
при сбое?2. Рекомендуется проверять наличие ошибок, если их могут вызвать некоторые вызовы функций, такие как вызовы функций OpenGL. Если вы проигнорируете их, вы можете наблюдать странное поведение.
3. @DanielLangr не могли бы вы подробнее рассказать?
4. @dvrer Смотри khronos.org/opengl/wiki/OpenGL_Error . Кроме того, в документации для каждой функции OpenGL перечислены конкретные ошибки, к которым может привести вызов функции.
Ответ №1:
Сбой в operator new
или new[]
может быть вызван:
- неудачное выделение. Например, если
infolen
слишком большой по сравнению с доступной памятью. - сбой в конструкторе выделяемых объектов. Но с
GLchar
это маловероятно.
Вы должны добавить код для обработки исключения, заключив new в блок try
.. catch
(как показано здесь), чтобы завершить работу корректно.
Если вы вызываете new с помощью nothrow
, вам следует затем проверить возвращаемый указатель на то, что он отличается от nullptr
, чтобы избежать неприятного UB.
Ответ №2:
Я вижу две проблемы с вашим кодом: во-первых, вы не проверяете, glGetShaderiv
успешно или нет; если нет, то infolen
остается неинициализированным. Меньшая проблема и единственная проблема при работе в средах с ошибками заключается в том, что вы не используете length
указатель glGetShaderInfoLog
для добавления нулевого ограничителя в конце; всегда рекомендуется извлекать это значение, а также проверять согласованность.
Также я предлагаю вам использовать std::string
вместо ручного выделения:
std::string infostring;
while( GL_NO_ERROR != glGetError() ); /* Flush Errors */
GLenum err;
glCompileShader( VSID );
if( GL_NO_ERROR == (err = glGetError())
){
GLint vstat = 0;
glGetShaderiv( VSID, GL_COMPILE_STATUS, amp;vstat );
if( (GL_NO_ERROR == (err = glGetError()))
amp;amp; vstat != GL_TRUE
){
GLint infolen = 0;
glGetShaderiv( VSID, GL_INFO_LOG_LENGTH, amp;infolen );
if( (GL_NO_ERROR == (err = glGetError()))
amp;amp; 0 < infolen
){
GLsizei returned_infolen = 0;
infostring = std::string(infolen, 0);
glGetShaderInfoLog( VSID, infolen, amp;returned_infolen, infostring.data() );
infostring.resize(returned_infolen);
err = glGetError();
}
}
if( GL_NO_ERROR != err
){
std::stringstream Error;
Error << "An Error occured while trying to compile"
" Vertex Shader "" << VertexShaderPath
<< "":nn" << infostring;
}