Как изменить мой метод обработки ошибок - PullRequest
0 голосов
/ 22 ноября 2010

Я не могу понять, почему люди говорят, что исключения в C ++ лучше.Например, у меня есть приложение, которое загружает функциональные объекты из общих объектов, которые будут использоваться в приложении.То, что происходит, выглядит примерно так:

bool LoadFunctions()
{
   //Get Function factory.
   FunctionFactory& oFactory = GetFunctionFactory();
   //Create functions from the factory and use.
}

FunctionFactory& GetFunctionFactory()
{
   //Get shared object handle.
   void* pHandle = dlopen("someso.so");

   //Get function ptr for Factory getter.
   typedef FunctionFactory* (*tpfFacGet)();
   tpfFacGet pF = static_cast<tpfFacGet>(dlsym(pHandle, "GetFactory"));

   //Call function and return object.
   return *((*pF)());
}

Теперь легко увидеть, что множество вещей может пойти не так.Если бы я делал это, как всегда, я бы возвращал указатели вместо ссылок, и я бы проверял, были ли они NULL, и печатал бы сообщение об ошибке, и получал, если это не так.Таким образом, я знаю, где что-то пошло не так, и могу даже попытаться восстановиться после этого (т. Е. Если я успешно загрузил фабрику и не смог загрузить только одну функцию, я все еще могу продолжить).Чего я не понимаю, так это как использовать исключения в таком сценарии и как восстановить программу, а не печатать сообщение об ошибке и квитировать.Может кто-нибудь сказать мне, как я это делаю в C ++ иш способом?

Ответы [ 3 ]

2 голосов
/ 22 ноября 2010

Нам даже не нужны коды возврата.Если возникает проблема, это должно быть в исключении.

int main()
{
    try
    {
        LoadFunctions();
        // if we're here, everything succeeded!
    }
    catch(std::exception _e)
    {
        // output exception message, quit gracefully
    } 

    // IRRESPECTIVE OF SUCCESS/FAILURE WE END UP HERE

    return 0;
} // eo main

РЕДАКТИРОВАТЬ:

Хорошо, давайте предположим, что у вас есть альтернативный метод загрузки функций в случае сбоя LoadFunctions().У вас может возникнуть соблазн вызвать это в обработчике catch, но таким образом вы быстро получите огромное количество вложенных обработчиков исключений, которые только усложняют ситуацию.

Так что теперь мы переходим к вопросу дизайн .LoadFunctions должно завершиться успешно, если функции загружены, и выкинуть исключение, если это не так.В этом гипотетическом примере альтернативного метода загрузки функций этот вызов должен быть внутри метода LoadFunctions.Этот альтернативный метод не должен быть видимым для вызывающей стороны.

На верхнем уровне мы либо получим функции, либо нет.Написание хорошей обработки исключений, на мой взгляд - это избавление от серых областей.Функция сделала то, что ей было сказано, или не сделала.

0 голосов
/ 22 ноября 2010

Использование исключений вместо возвращаемых значений (или любого другого метода) не должно изменять поведение кода, а только то, как он написан и организован.По сути, это означает, что сначала вы решаете, как будет восстанавливаться определенная ошибка, будь она более изящной или менее, а затем пишете код для ее выполнения.Большинство опытных программистов (все практически) согласны с тем, что исключения являются гораздо лучшим методом, чем возвращаемые значения.Вы не увидите большой разницы в коротких примерах нескольких функций, но в реальных системах тысяч функций и типов вы бы это ясно увидели.Я не буду вдаваться в подробности того, как это лучше.В любом случае, я предлагаю вам привыкнуть к использованию исключений по умолчанию.Однако обратите внимание, что использование исключений имеет некоторые довольно деликатные проблемы (например, RAII http://en.wikipedia.org/wiki/RAII),, которые в конечном итоге делают ваш код лучше, но вы должны прочитать о них в книге (я не смогу описать здесь и чувствую, что я это делаю)справедливость к предмету.) Я думаю, что книга "Эффективный c ++ / Скотт Мейер" имеет дело с этим, конечно "Исключительный C ++ / Herb Sutter". Эти книги - хороший старт для любого разработчика c ++, если вы все равно их не читали.

0 голосов
/ 22 ноября 2010

Как вы говорите, многое может пойти не так.Кстати, плохого актера там не поймаешь.Если символ существует, но не относится к тому типу, к которому вы его применяете, вы просто получите неприятный шок позже.

Если вы избегаете исключений, вам нужно где-то сообщить об ошибке.Поскольку ваши LoadFunctions и GetFunctionFactory () не знают, как вы хотите обработать ошибку (зарегистрировать ее, распечатать на stderr? Поднять окно сообщения?), Единственное, что он может сделать, - это сгенерировать ошибку.

Обычный способ сделать это в C состоит в том, чтобы передать параметр, в который он может поместить ошибку, если таковая возникает, и для каждой функции «проверить» успешность перед продолжением.Это может сделать поток довольно сложным.

Концепция «выброса» исключения в C ++ означает, что вам не нужно постоянно передавать указатель (или ссылку) через каждую функцию.Там, где возникает ошибка, вы генерируете ее и «выбрасываете» - немного похоже на «крик».Это приводит к тому, что весь код (кроме очистки в деструкторах) останавливается до тех пор, пока не найдет перехватчик, который обрабатывает ошибку требуемым образом.

Обратите внимание, что исключения должны обычно использоваться только для обработки ошибок, а не в обычном случаенапример, встреча с «концом файла», когда вы знаете, что чтение завершено.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...