跳过代码不使用状态变量,使用goto设想
Skip code without using state variable, using goto envisaged
我有一个代码,其中有部分不能执行,如果有一个错误之前的代码。我实际上使用了一个名为EndProg
的bool变量,如果将其设置为true
,将指示程序避免执行某些部分的代码。
我的问题是,我不想使用这种方法,我宁愿使用goto
代替,因为它会使程序跳转到清理部分,避免多次检查EndProg
值。
另一个问题是,我在StackOverflow和其他网站的许多页面上读到,使用goto
被认为是一种不好的做法,它可以使代码更难以阅读或产生错误。
我的代码很简单,我只需要使用一个标签,所以我怀疑这会产生问题;但我想知道是否有其他方法可以做我想做的事情,而不需要创建函数来执行清理任务或使用return
(因为,例如,我需要多次编写清理代码),我也不想在多个地方编写相同的大清理代码,然后使用return
或做其他事情。
我不想增加代码行数,也不想使用return
或使用大量if
,也不想检查状态变量的值。你有什么建议吗?
下面是一段代码:
bool EndProg=false;
/*
Lot of code that can set EndProg to true
*/
ClassType ClassName;
if(!EndProg && LoadConf(&ConfFilePath,&ClassName)==0)
{
int fildes=-1;
if(ClassName.abc) // bool
{
if(ClassName.FilePath==0) // char *
{
ClassName.FilePath=new(std::nothrow) char[9]();
if(ClassName.FilePath!=0)strcpy(ClassName.FilePath,"file.ext");
else EndProg=true;
}
if(!EndProg && mkfifo(ClassName.FilePath,S_IRUSR | S_IWUSR)==-1)
{
if(errno==EEXIST)
{
/* EEXIST is returned if the file already exists
We continue, later we will try to open this file */
}
else EndProg=true;
}
if(!EndProg && (fildes=open(ClassName.FilePath,O_RDWR))==-1)EndProg=true;
}
/*
Lot of code that will check if EndProg == true
*/
}
delete[] ClassName.FilePath;
delete[] ConfFilePath;
我想做的是:
bool EndProg=false;
/*
Lot of code that can set EndProg to true
*/
ClassType ClassName;
if(LoadConf(&ConfFilePath,&ClassName)==0)
{
int fildes=-1;
if(ClassName.abc) // bool
{
if(ClassName.FilePath==0) // char *
{
ClassName.FilePath=new(std::nothrow) char[9]();
if(ClassName.FilePath==0)goto cleanup;
strcpy(ClassName.FilePath,"file.ext");
}
if(mkfifo(ClassName.FilePath,S_IRUSR | S_IWUSR)==-1)
{
if(errno==EEXIST)
{
/* EEXIST is returned if the file already exists
We continue, later we will try to open this file */
}
else goto cleanup;
}
if((fildes=open(ClassName.FilePath,O_RDWR))==-1)goto cleanup;
}
/*
Lot of code that will check if EndProg == true
*/
}
cleanup:
delete[] ClassName.FilePath;
delete[] ConfFilePath;
正如你所看到的,这并不难理解,即使搜索标签对某些人来说可能是一个问题,但对我来说不是;我不打算把代码公开。
更新:
我决定使用异常,它对我原始代码的某些部分有效。但我怀疑这在更复杂的部分是否容易实现。谢谢你的回答。
既然你已经标记了这个问题c++
,我也会使用异常和try
catch
块。
你可以在SO和其他网站上找到很多关于这个主题的有用信息:
这是一个非常基础的教程。
这里有一个很好的基本的常见问题解答,可能也会对你有所帮助。
基本上没有什么好害怕的,异常并不神秘,事实上,当你掌握了它的窍门时,它更有意义。因为基本上这个概念可以让你实现你想要的:
可以由相同的错误处理代码处理的几个缺陷。
编辑:例如,如果我将mkfifo
等移动到一个函数中(通常为每个定义良好的逻辑块创建一个函数更清晰,更可读),并具有类似
这只是一个草图给你一个大致的概念:
#include <exception>
functionThatDoesMakeFifo(...){
// check which ever conditions you want to check after mkfifo
// if one of them goes wrong just do:
throw std::exception();
}
// this is inside your function:
ClassType ClassName;
try{
ClassName.FilePath = new char[9](); // even though I'd use a string...
.
.
. // rest of the code
} catch(std::exception &e){
delete [] ClassName.FilePath;
delete [] ConfFilePath;
ClassName.FilePath = NULL; // not mandatory just my habit
ConfFilePath = NULL;
}
我会尝试使用范围保护或BOOstrongCOPE_EXIT (c++)或其c++ 11类似的东西:
template<class F>
struct ScopeExit
{
ScopeExit(F f) : f(f) {}
~ScopeExit() { f(); }
F f;
};
template<class F>
ScopeExit<F> MakeScopeExit(F f) { return ScopeExit<F>(f); }
#define STRING_JOIN2(arg1, arg2) DO_STRING_JOIN2(arg1, arg2)
#define DO_STRING_JOIN2(arg1, arg2) arg1 ## arg2
#define SCOPE_EXIT(code)
auto STRING_JOIN2(scope_exit_, __LINE__) = MakeScopeExit([=](){code;})
bool myfunct()
{
ClassType ClassName;
ClassName.FilePath = 0;
ConfFilePath = 0;
SCOPE_EXIT(delete [] ClassName.FilePath; delete [] ConfFilePath; );
if (LoadConf(&ConfFilePath,&ClassName) == 0)
{
int fildes=-1;
if(ClassName.abc) // bool
{
if(ClassName.FilePath==0) // char *
{
ClassName.FilePath=new(std::nothrow) char[9]();
if(ClassName.FilePath==0) return false;
strcpy(ClassName.FilePath,"file.ext");
}
if(mkfifo(ClassName.FilePath,S_IRUSR | S_IWUSR)==-1)
{
if (errno==EEXIST)
{
/* EEXIST is returned if the file already exists
We continue, later we will try to open this file */
}
else return false;
}
if((fildes=open(ClassName.FilePath,O_RDWR))==-1) return false;
}
/*
Lot of code that will check if EndProg == true
*/
}
return true;
}
我使用return
,但清理代码只是在一个地方。
无论如何,ClassName
应该负责清理析构函数中自己的资源。
我以前见过一个小技巧可以帮助您解决这个问题,尽管我个人不喜欢技巧,但它可能适合您的需要。
while (true)
{
if(ClassName.FilePath==0) // char *
{
ClassName.FilePath=new(std::nothrow) char[9]();
if(ClassName.FilePath==0) break;
strcpy(ClassName.FilePath,"file.ext");
}
if(mkfifo(ClassName.FilePath,S_IRUSR | S_IWUSR)==-1)
{
if(errno==EEXIST)
{
/* EEXIST is returned if the file already exists
We continue, later we will try to open this file */
}
else break;
}
if((fildes=open(ClassName.FilePath,O_RDWR))==-1) break;
/*
Lot of code that will check if EndProg == true
*/
break;
}
delete[] ClassName.FilePath;
delete[] ConfFilePath;
但是我也不认为这是一个优雅的解决方案,我个人会重写你的代码,把它分解成更容易读的东西。但是,我也不写包含数百行的函数。
我可能会被投反对票,但我认为在C语言中有限地使用goto并不是坏事。特别是,您所谈论的是完全可以接受的:向前分支以清除错误代码。我建议您将此限制为每个例程一个目标标签。
人们讨厌的(有理由的)是老式的意大利面条式代码,到处都是goto。
- 对类 (C++) 中的私有变量使用未声明的标识符
- 当对字符变量使用toupper()时,所述char变量输出多个字符.我该如何防止这种情况发生
- 将子类实例保存在父类型变量中并通过父变量使用 Child 函数?
- 为什么 c++ 编译器在对两种不同类型的数值变量使用"std::max()"函数时会出现错误
- 错误 C4703 可能未初始化的局部指针变量'y'使用
- 在使用结构体和用函数填充其变量(使用指针)时遇到问题
- 在不同的文件中使用相同的变量(使用 extern)
- 使用 INSTALLS 变量使用 Qmake 安装依赖项
- 这是未初始化的变量使用未定义的行为吗
- 通过其他文件中的另一个全局变量使用类的全局实例
- Qt4 C++:来自多个线程的QString变量使用崩溃
- 对成员类/对象变量使用指针更好吗
- 是否可以在c++中为变量使用动态名称
- 对条件变量使用Char
- C++中的超时变量使用什么类型
- 为什么对数值变量使用 cin "bad"?
- 删除由多个变量使用的指针
- 通过变量使用对象和对象函数
- C++:全局变量与局部变量.使用什么
- 为LLVM中的变量使用特定的寄存器