Я использую tinyxml для парсинга XML-файлов, и я нашел, что обработка ошибок здесь предоставляет себя коду стрелки. Наша обработка ошибок просто сообщает о сообщении файлу.
Вот пример:
const TiXmlElement *objectType = dataRoot->FirstChildElement( "game_object" );
if ( objectType ) {
do {
const char *path = objectType->Attribute( "path" );
if ( path ) {
const TiXmlElement *instance = objectType->FirstChildElement( "instance" );
if ( instance ) {
do {
int x, y = 0;
instance->QueryIntAttribute( "x", &x );
instance->QueryIntAttribute( "y", &y );
if ( x >= 0 && y >= 0 ) {
AddGameObject( new GameObject( path, x, y ));
} else {
LogErr( "Tile location negative for GameObject in state file." );
return false;
}
} while ( instance = instance->NextSiblingElement( "instance" ));
} else {
LogErr( "No instances specified for GameObject in state file." );
return false;
}
} else {
LogErr( "No path specified for GameObject in state file." );
return false;
}
} while ( objectType = objectType->NextSiblingElement( "game_object" ));
} else {
LogErr( "No game_object specified in <game_objects>. Thus, not necessary." );
return false;
}
return true;
Я не раздражаю и пыхчу по нему, но если бы кто-либо может думать о более чистом способе выполнить это, это ценилось бы.
P.S. Исключения не опция.
Править:
Что-то вроде этого было бы предпочтительно?
if ( !path ) {
// Handle error, return false
}
// Continue
Это устраняет код стрелки, но код стрелки отчасти помещает всю регистрацию ошибок на одном месте.
Использование возвращаемых значений в качестве кодов ошибок просто приводит к такому коду, его нельзя значительно улучшить. Немного более чистый способ - использовать goto
, чтобы сгруппировать всю обработку ошибок в один блок и уменьшить вложение блоков.
Однако это не решает реальной проблемы, заключающейся в использовании возвращаемых значений в качестве кодов ошибок. В C нет альтернативы, но в C ++ есть исключения, и их следует использовать. Если они не подходят, вы застряли с тем, что у вас есть.
Для этого можно создать макрос, который инкапсулирует if (!var) { ... return false; }
и отчет об ошибках.
Однако я не вижу, как это можно улучшить; это просто то, что есть. C'est la vie. C'est le code...
Я не фыркаю над этим, но если кто может придумать уборщика способ добиться этого было бы оценен.
Я заменил вложенные ifs операторами return в случае ошибки (это заставляет код «течь вниз» вместо того, чтобы идти «в форме стрелки». Я также заменил ваши do loopps на циклы for (чтобы я мог лучше понять это).
Это то, что вы хотели?
const TiXmlElement *objectType = dataRoot->FirstChildElement( "game_object" );
if ( !objectType ) {
LogErr( "No game_object specified in <game_objects>. Thus, not necessary." );
return false;
}
for(; objectType != 0; objectType = objectType->NextSiblingElement( "game_object" )) {
const char *path = objectType->Attribute( "path" );
if ( !path ) {
LogErr( "No path specified for GameObject in state file." );
return false;
}
const TiXmlElement *instance = objectType->FirstChildElement( "instance" );
if ( !instance ) {
LogErr( "No instances specified for GameObject in state file." );
return false;
}
for(; instance != 0; instance = instance->NextSiblingElement( "instance" )) {
int x, y = 0;
instance->QueryIntAttribute( "x", &x );
instance->QueryIntAttribute( "y", &y );
if ( x >= 0 && y >= 0 ) {
AddGameObject( new GameObject( path, x, y ));
} else {
LogErr( "Tile location negative for GameObject in state file." );
return false;
}
}
}
return true;