Здравствуйте, barmafon, Вы писали:
TC>>еще один вариант — "липовый" do {}while(0);
TC>>плюсы :
TC>> + в любом месте можно выйти из него простым break не заботясь о вызове деструкторов
TC>> + все деструкторы вызываются в одном месте
TC>> + несмотря на похожесть на вариант с goto тут нет меток
TC>> + внутри do {} while() можно завести какой локальный объект внутри тела блока.
TC>> минусы :
TC>> — кому то может показаться что do {} while() используется не по делу)
TC>> — код все таки уползает вправо хотя и медленно.
TC>> — проверки на NULL режут глаз
B>для устранения минуса №3 можно воспользоваться следующей техникой:
B>B>int f()
B>{
B> int stage, failed;
B> void *obj1;
B> void *obj2;
B> for( stage = 0;; ) {
B> if( !(failed=construct_obj1(&obj1)) )
B> break;
B> ++stage;
B> if( !(failed=construct_obj2(&obj2)) )
B> break;
B> ++stage;
B> if( !(failed=do_something(obj1,obj2)) )
B> break;
B> ++stage;
B> break;
B> }
B> switch( stage ) {
B> case 3: break;
B> case 2: destruct_obj2(obj1);
B> case 1: destruct_obj1(obj1);
B> }
B> return failed;
B>}
B>
B>плюсы:
B>+ красиво
B>+ мы не обязаны инициализировать указатели на создаваемые объекты
B>минусы:
B>- нужна специальная переменная stage
B>- отслеживание значений переменной stage в каждой точке инициализации
Может воспользоватся макросами :
int f()
{
void *obj1;
void *obj2;
BEGIN_ERROR()
BEGIN_INIT()
ERROR_INIT1(construct_obj1,&obj1)
ERROR_INIT1(construct_obj2,&obj2)
ERROR_INIT2(do_something,&obj1,&obj2)
END_INIT()
BEGIN_TEST()
ERROR_TEST(3)
ERROR_TEST1(2,destruct_obj2,&obj2)
ERROR_TEST1(1,destruct_obj1,&obj1)
END_TEST()
END_ERROR()
}
Сами макросы :
#define STAGE_VAR \
stage_unique_name__
#define FAILED VAR \
failed_unique_name__
#define BEGIN_ERROR() \
{ \
int STAGE_VAR=0; \
int FAILED_VAR=0;
#define END_ERROR() \
return FAILED_VAR; \
}
#define BEGIN_INIT() \
while(1) \
{
#define END_INIT() \
break; \
}
#define ERROR_INIT0(f) \
if(!(FAILED_VAR=f())) \
break; \
++STAGE_VAR;
#define ERROR_INIT1(f,p1) \
if(!(FAILED_VAR=f(p1))) \
break; \
++STAGE_VAR;
#define ERROR_INIT2(f,p1,p2) \
if(!(FAILED_VAR=f(p1,p2))) \
break; \
++STAGE_VAR;
#define BEGIN_TEST() \
switch(STAGE_VAR) \
{
#define END_TEST() \
}
#define ERROR_TEST(n) \
case n: break;
#define ERROR_TEST0(n,f) \
case n: f();
#define ERROR_TEST1(n,f,p1) \
case n: f(p1);
#define ERROR_TEST2(n,f,p1,p2) \
case n: f(p1,p2);