我有一个程序,其中需要跳出一大堆嵌套的for循环。到目前为止,大多数人告诉我在代码中使用丑陋的goto命令来实现。
那么,如果我在循环内部创建了许多本地堆栈(我认为这就是它们的名称,如果不是,我指的是只使用常规变量而不使用new命令的变量),并且我的程序触发了那个if语句以触发goto命令,是否会因为程序未正确清理本地变量而导致内存泄漏?
我有一个程序,其中需要跳出一大堆嵌套的for循环。到目前为止,大多数人告诉我在代码中使用丑陋的goto命令来实现。
那么,如果我在循环内部创建了许多本地堆栈(我认为这就是它们的名称,如果不是,我指的是只使用常规变量而不使用new命令的变量),并且我的程序触发了那个if语句以触发goto命令,是否会因为程序未正确清理本地变量而导致内存泄漏?
不会引起内存泄漏。使用goto
并非“不正确退出循环”,仅是从代码结构的角度来看通常不建议使用。
除此之外,当您离开循环时,局部变量将超出作用域并在过程中弹出堆栈(即被清理)。
栈变量(自动变量,不是自动机器人)不像通过new()或malloc()分配的变量那样“泄漏”。
至于goto语句的“丑陋”,那只是教条主义。阅读 Knuth,他和 Dijkstra 一样聪明。http://pplab.snu.ac.kr/courses/adv_pl05/papers/p261-knuth.pdf避免基于意大利面的编程,但仔细使用不会退化成意大利面条。
Dijkstra 不喜欢它们,因为大多数可以使用其他结构化编程技术完成的goto操作可以使用更少的代码完成,从而使其他结构化编程方法更少出错。
要理解的是,goto不应该是您的第一个解决方案,也不要费力地使用它们,但如果有意义,请不要屈服于教条的暴民。break语句只是一个伪装成goto的命令,旨在处理严格遵守“不得使用goto”的规则不合理的情况。
在进入函数时,栈变量被定义(和分配),一旦离开函数,它们就会被隐式消除(因为整个调用堆栈记录已经弹出)。无论在函数内部如何反复跳动,都不可能对一直分配的内存造成任何破坏。无论你通过代码走哪条执行路径,当控制返回到调用函数时,堆栈记录将弹出,内存将被释放。
Goto并不总是不好的,但在您的情况下,您可能不应该使用goto。
如果您跳转到超出范围的标签,则堆栈上的对象将被释放。
例如:
#include <iostream>
using namespace std;
class A
{
public:
~A()
{
cout<<"A destructor"<<endl;
}
};
int main(int argc, char**argv)
{
{
A a;
cout<<"Inside scope"<<endl;
goto l;
cout<<"After l goto"<<endl;
}
cout<<"Outside of scope before l label"<<endl;
l:
cout<<"After l label"<<endl;
return 0;
}
作用域内
一个析构函数
标签 l 之后
倒退跳转会泄漏资源吗?或者以下代码还存在其他潜在问题吗?
重新执行:
try
{
//Setup request
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
....
//Get Response
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
if(response != HttpStatus.OK && noOfRetries < 3)
{
noOfRetries++;
Thread.Sleep(10 * 1000);
response.Close();
goto Reexecute;
}
...
response.Close();
}
catch
{
}
不,你不会这样做。
然而,请确保任何外部资源都被正确释放。例如,如果你打开了一个文件,可能会跳过它通常关闭的位置。
不需要。局部变量不需要单独清理。当堆栈弹出时,所有局部变量也会随之消失。
不,如果您使用goto语句跳出循环,那么循环中的任何自动变量都不会导致编程泄漏。
goto
并不会(太)有害。但我想引用这个答案中的第一个评论:“+1:如果需要考虑使用 goto,则它足够复杂,可以封装在函数中避免使用 goto。”:https://dev59.com/JXNA5IYBdhLWcg3wSrua#1024395. - R. Martinho Fernandesreturn
看作是一个结构化的goto
。如果一个return
会泄漏,那么一个goto
也会泄漏。 (而且,当你在这方面时,考虑使用结构化方法代替意大利面条式方法,将代码放入自己的函数中并使用return
跳出。Martinho 引用的经验法则非常好。) - sbi