2015-05-28 4 views
1

Я проект, основные выглядетьC++ код стал не линейным при использовании исключения

Object a; 

if (! a.initialize(x, y, z)) 
    return EXIT_FAILURE; 

// 100 lines using a 

a.finalize(); 

Я пытался изменить эту часть кода и с помощью RAII idiome. Итак, я удаляю функцию initialize и finalize и перемещаю код в конструкторе и деструкторе.

Чтобы уловить ошибку initialize(), я создаю исключение в конструкторе, если что-то не работает.

Итак, мой код выглядит следующим образом:

try 
{ 
    Object a(x, y, z); 

    // 100 lines using a 
} catch (my_exception&) 
{ 
    return EXIT_FAILURE; 
} 

думать, что беспокоит это 100 строк кода. Мой try слишком длинный для одной ошибки. И у меня есть несколько объектов вроде a.

поэтому перед мой код был линейным:

Object a; 

if (! a.initialize(x, y, z)) 
    return EXIT_FAILURE; 

Object b; 
Object c; 

if (!b.initialize() || !c.initialize()) 
    return EXIT_FAILURE; 

a.finalize(); 

Теперь это выглядит некрасиво, трудно читать:

try 
{ 
    Object a(x, y, z); 

    try 
    { 
    Object b; 
    try 
    { 
     Object c; 
    } 
    catch (my_exception_c&) 
    { 
     return EXIT_FAILURE; 
    } 
    } 
    catch (my_exception_b&) 
    { 
    return EXIT_FAILURE; 
    }  

} catch (my_exception&) 
{ 
    return EXIT_FAILURE; 
} 

Как сделать, чтобы использовать RAII и сохранить код ясно?

+0

Не чистая RAII - это то, где ctors может выйти из строя без метания, а объекты RAII записывают такой сбой. Он похож на гибрид ваших двух примеров, но очистка ресурсов происходит автоматически в предложениях об ошибке возврата. – Yakk

ответ

5

В целом создайте блок try на уровне, на котором вы хотите обработать исключение. В этом случае вам просто нужен блок верхнего уровня для очистки после любого исключения:

try { 
    Object a(x, y, z); 
    Object b; 
    Object c; 

    // code using these 

} catch (...) { 
    // end the program if any exception hasn't been handled 
    return EXIT_FAILURE; 
} 

Теперь это не «слишком долго для одной ошибки»; это правильная длина для любой ошибки, которая может возникнуть.

Было бы неплохо ограничить себя исключениями, полученными от std::exception; то вы могли бы дать некоторые потенциально полезную информацию в том случае, если она не обрабатывается:

catch (std::exception const & ex) { 
    std::cerr << "ERROR: " << ex.what() << std::endl; 
    return EXIT_FAILURE; 
} 
1

Вам нужно только один улов, как это:

try 
{ 
    Object a; 
    Object b; 
    //100 lines of code 
} 
catch(ExeptionA& exa) 
{ 
    cerr << "error a" << endl; 
} 
catch(ExeptionB& exa) 
{ 
    cerr << "error B" << endl; 
} 
catch(...){ 
    cerr << "some other error" << endl; 
} 

(причем «...» буквально означает».. . ')

Таким образом, вы поймаете все исключения из объектов ObjectA и ObjectB и т. Д. В том же улове. Поэтому, если вы создадите собственное исключение, может быть полезно добавить некоторую информацию там, откуда она появилась.

1

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

 Смежные вопросы

  • Нет связанных вопросов^_^