Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/136.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ “避免的模式”;如果清理失败”;重复_C++_C_Design Patterns - Fatal编程技术网

C++ “避免的模式”;如果清理失败”;重复

C++ “避免的模式”;如果清理失败”;重复,c++,c,design-patterns,C++,C,Design Patterns,我有一些代码如下所示: int myfunc() { blah a; blah2 b; blah3 c; blah4 d; blah5 e; int iRes = DoSomething1(a, b, c); if (iRes > 0) { clean1(a, b, c); clean2(d, e); log_error(); retur

我有一些代码如下所示:

int myfunc()
{
     blah a;
     blah2 b;
     blah3 c;
     blah4 d;
     blah5 e;

     int iRes = DoSomething1(a, b, c);
     if (iRes > 0)
     {
         clean1(a, b, c);
         clean2(d, e);
         log_error();
         return 1;
     }

     iRes = DoSomething2(a, c, e);
     if (iRes > 0)
     {
         clean1(a, b, c);
         clean2(d, e);
         log_error();
         return 1;
     }

     ...

     iRes = DoSomething10(c, d, e);
     if (iRes > 0)
     {
         clean1(a, b, c);
         clean2(d, e);
         log_error();
         return 1;
     }

     clean1(a, b, c);
     clean2(d, e);
     return 0;
}
<> >强> >如何在C或C++中避免重复<代码>(ILR> 0){CURL1(A,B,C);CURL2(D,E);LogError();返回1;}在每个函数调用之后< <强> >/P>
注:

  • 在实际代码中,这些函数
    DoSomethingx()
    cleanx()
    都是API函数,不是我自己编写的
  • 我希望避免在
    myfunct()
    之外定义第二个函数
    clean()
    ,该函数将处理cleanup+错误
  • 我曾考虑过使用预处理器宏,但我怀疑这对于这种情况是否是一种好的做法
例如:


就是这样一个例子:每10行代码实际上是=2行,仅用于实际执行某项操作+8行错误测试和清理。。。我们能做得更好吗?

正如贾斯汀提到的,答案会因语言的不同而大不相同

如果你在C语言中,这是
goto
在该语言中占有一席之地的最后一个地方。例如,如果您有:

int myfunc()
{
胡说八道;
blah2 b;
blah3-c;
blah4d;
blah5-e;
int iRes=DoSomething1(a,b,c);
如果(iRes>0)
{
转到错误清除;
}
iRes=DoSomething2(a,c,e);
如果(iRes>0)
{
转到错误清除;
}
/*...*/
iRes=DoSomething10(c,d,e);
如果(iRes>0)
{
转到错误清除;
}
/*成功*/
清洁1(a、b、c);
清洁2(d,e);
返回0;
/*错误退出点*/
错误\u清除:
清洁1(a、b、c);
清洁2(d,e);
log_error();
返回1;
}

但是,在C++中,我们需要处理这个清理代码,即使抛出异常,也会让其他方案陷入困境。然而,在C++中,我们也有RAII,这意味着析构函数就是去路。

< P>正如贾斯廷所提到的,答案将是完全不同的,这取决于语言。 如果你在C语言中,这是
goto
在该语言中占有一席之地的最后一个地方。例如,如果您有:

int myfunc()
{
胡说八道;
blah2 b;
blah3-c;
blah4d;
blah5-e;
int iRes=DoSomething1(a,b,c);
如果(iRes>0)
{
转到错误清除;
}
iRes=DoSomething2(a,c,e);
如果(iRes>0)
{
转到错误清除;
}
/*...*/
iRes=DoSomething10(c,d,e);
如果(iRes>0)
{
转到错误清除;
}
/*成功*/
清洁1(a、b、c);
清洁2(d,e);
返回0;
/*错误退出点*/
错误\u清除:
清洁1(a、b、c);
清洁2(d,e);
log_error();
返回1;
}

但是,在C++中,我们需要处理这个清理代码,即使抛出异常,也会让其他方案陷入困境。但是,在C++中,我们也有RAII,这意味着析构函数是要走的路。

< P>这是我喜欢的一个技巧,避免了Goto:

bool success = false;

do {
    r = do_something();
    if (r) break;

    r = do_something_else();
    if (r) break;

    r = do_something_again();
    if (r) break;

    success = true;
} while(0);

if (! success) {
    clean_up();
}

这里有一个我喜欢的技巧,可以避免跳槽:

bool success = false;

do {
    r = do_something();
    if (r) break;

    r = do_something_else();
    if (r) break;

    r = do_something_again();
    if (r) break;

    success = true;
} while(0);

if (! success) {
    clean_up();
}

对于给定的代码,您可以在其上使用以下任意一种变体:

int myfunc()
{
     blah a;
     blah2 b;
     blah3 c;
     blah4 d;
     blah5 e;

     int iRes;
     if ((iRes = DoSomething1(a, b, c)) > 0 ||
         (iRes = DoSomething2(a, c, e)) > 0 ||
         ...
         (iRes = DoSomething10(c, d, e)) > 0)
     {
         clean1(a, b, c);
         clean2(d, e);
         log_error();
         return 1;
     }

     clean1(a, b, c);
     clean2(d, e);
     return 0;
}
如果在
clean1()
clean2()
之前或之后调用
log\u error()
并不重要,您可以使用:

int myfunc()
{
     blah a;
     blah2 b;
     blah3 c;
     blah4 d;
     blah5 e;

     int iRes;
     if ((iRes = DoSomething1(a, b, c)) > 0 ||
         (iRes = DoSomething2(a, c, e)) > 0 ||
         ...
         (iRes = DoSomething10(c, d, e)) > 0)
     {
         log_error();
     }

     clean1(a, b, c);
     clean2(d, e);
     return 0;
}
甚至:

int myfunc()
{
     blah a;
     blah2 b;
     blah3 c;
     blah4 d;
     blah5 e;

     int iRes;
     if ((iRes = DoSomething1(a, b, c)) > 0 ||
         (iRes = DoSomething2(a, c, e)) > 0 ||
         ...
         (iRes = DoSomething10(c, d, e)) > 0)
     {
         // Don't need to do anything here
     }

     clean1(a, b, c);
     clean2(d, e);
     if (iRes > 0)
         log_error();
     return 0;
}
if
的主体可能是最终赋值:

int myfunc()
{
     blah a;
     blah2 b;
     blah3 c;
     blah4 d;
     blah5 e;

     int iRes;
     if ((iRes = DoSomething1(a, b, c)) > 0 ||
         (iRes = DoSomething2(a, c, e)) > 0 ||
         ...
        )
     {
         iRes = DoSomething10(c, d, e);
     }

     clean1(a, b, c);
     clean2(d, e);
     if (iRes > 0)
         log_error();
     return 0;
}

这种重构依赖于清理在所有情况下都是相同的。通常情况下,它不是很系统。由于没有显示正在初始化的
a
b
c
d
e
中的任何一个,因此很难确定什么是真正安全的。如果<代码> DOMMETHONGEN()/COD>函数在C++中并引用引用,则<代码> DOOMETHONGIN()/Cyto>可以初始化<代码> A<代码> <代码> B<代码> >代码> C>代码> ->对<代码> Cuff2()的调用>代码>可以发生在d或E>代码>的值之间.对于给定代码,

< P>您可以在其上使用多种变体中的任意一种:

int myfunc()
{
     blah a;
     blah2 b;
     blah3 c;
     blah4 d;
     blah5 e;

     int iRes;
     if ((iRes = DoSomething1(a, b, c)) > 0 ||
         (iRes = DoSomething2(a, c, e)) > 0 ||
         ...
         (iRes = DoSomething10(c, d, e)) > 0)
     {
         clean1(a, b, c);
         clean2(d, e);
         log_error();
         return 1;
     }

     clean1(a, b, c);
     clean2(d, e);
     return 0;
}
如果在
clean1()
clean2()
之前或之后调用
log\u error()
并不重要,您可以使用:

int myfunc()
{
     blah a;
     blah2 b;
     blah3 c;
     blah4 d;
     blah5 e;

     int iRes;
     if ((iRes = DoSomething1(a, b, c)) > 0 ||
         (iRes = DoSomething2(a, c, e)) > 0 ||
         ...
         (iRes = DoSomething10(c, d, e)) > 0)
     {
         log_error();
     }

     clean1(a, b, c);
     clean2(d, e);
     return 0;
}
甚至:

int myfunc()
{
     blah a;
     blah2 b;
     blah3 c;
     blah4 d;
     blah5 e;

     int iRes;
     if ((iRes = DoSomething1(a, b, c)) > 0 ||
         (iRes = DoSomething2(a, c, e)) > 0 ||
         ...
         (iRes = DoSomething10(c, d, e)) > 0)
     {
         // Don't need to do anything here
     }

     clean1(a, b, c);
     clean2(d, e);
     if (iRes > 0)
         log_error();
     return 0;
}
if
的主体可能是最终赋值:

int myfunc()
{
     blah a;
     blah2 b;
     blah3 c;
     blah4 d;
     blah5 e;

     int iRes;
     if ((iRes = DoSomething1(a, b, c)) > 0 ||
         (iRes = DoSomething2(a, c, e)) > 0 ||
         ...
        )
     {
         iRes = DoSomething10(c, d, e);
     }

     clean1(a, b, c);
     clean2(d, e);
     if (iRes > 0)
         log_error();
     return 0;
}

这种重构依赖于清理在所有情况下都是相同的。通常情况下,它不是很系统。由于没有显示正在初始化的
a
b
c
d
e
中的任何一个,因此很难确定什么是真正安全的。如果<代码> DOMMETHONGEN()/CUT>函数在C++中,并通过引用来引用,那么<代码> DOOMETHONGIONS(/CUT>)可以初始化<代码> A<代码> <代码> B<代码> >代码> C++ >代码>但是,对<代码> Cuff2()的调用>代码>可以在d>代码>或 E>代码>之前出现。答案会因你是谁而大不相同using@Basj他们将非常不同。在C++中,你将使用RAII。C没有RAIIIn的C++案例,如果错误不太常见,就会抛出并捕获异常。这将收集大部分(如果不是全部的话)@Basj基本上,您会使
DoSomethingN
抛出异常,而不是通过返回值标记错误。如果
DoSomethingN
超出了您的控制范围,因为它是一个外部库,您应该将它包装起来以抛出异常。@Basj这些问题必须是两个独立的问题。事实上,它标记为[C++ +]和[c]使得C++或C++使用得太宽了吗?答案会因你是谁而大不相同using@Basj他们将非常不同。在C++中,你将使用RAII。C没有RAIIIn的C++案例,如果错误不太常见,就会抛出并捕获异常。这将收集大部分(如果不是全部的话)@Basj基本上,你会让
DoSomethingN
抛出一个例外