goto的好处
向来都是 不要用goto,破坏可读性,容易是bug频出。我也深信不疑。
最近维护一个程序代码,包了N多层了(超过5层),里面有while if for,
我在跳出来的时候用了一次goto,还挺好用,但是没发现什么异常。
网上百度了一下goto总结了一下他的作用:
不使用goto
int i = 0, j = 0;
while( true )
{
while ( true )
{
if ( 4 == j )
break;
j++;
}
If ( 4 == i )
break;
}
i++;
}
int i = 0, j = 0;
while( true )
{
while ( true )
{
if ( 4 == j )
break;
j++;
}
If ( 4 == i )
break;
}
i++;
}使用goto
int i = 0, j = 0;
while ( true )
{
while ( true )
{
if ( 4 == j && 4 == i )
goto EXIT_WHILE;
j++;
}
i++;
}
EXIT_WHILE:
...
int i = 0, j = 0;
while ( true )
{
while ( true )
{
if ( 4 == j && 4 == i )
goto EXIT_WHILE;
j++;
}
i++;
}
EXIT_WHILE:
...如果不使用goto,很难一下子看出循环出口是i=4,j=4。而用了goto之后这一点变得一目了然了,而EXIT
标记就在循环外,很好找,所以代码的可读性并没有降低多少。
看Microsoft的msxml—sdk里面的例子,他用了goto
#include <stdio.h>
#include <msxml2.h>
// You might need to add the msxml4/sdk/(inc, lib) directories
// to the Tools->Options...->Directories in Visual Studio.
//
// You might also need to append "msxml2.lib" to the
// Project->Settings...->Link->Object/Libray Modules field.
int main(int argc, char* argv[])
{
HRESULT hr;
IXMLDOMDocument3 *pXMLDoc = NULL;
IXMLDOMParseError * pObjError = NULL;
BSTR bstr = NULL;
VARIANT_BOOL status;
VARIANT vSrc;
CoInitialize(NULL);
hr = CoCreateInstance(CLSID_DOMDocument40,
NULL,
CLSCTX_INPROC_SERVER,
IID_IXMLDOMDocument3,
(void**)&pXMLDoc);
if (FAILED(hr))
{
printf("Failed to CoCreate an instance of an XML DOM/n");
printf("Error code: %x/n", hr);
goto clean;
}
hr = pXMLDoc->put_async(VARIANT_FALSE);
if (FAILED(hr))
{
printf("Failed to set async property/n");
goto clean;
}
hr = pXMLDoc->put_validateOnParse(VARIANT_FALSE);
if (FAILED(hr))
{
printf("Failed to set validateOnParse/n");
goto clean;
}
hr = pXMLDoc->put_resolveExternals(VARIANT_FALSE);
if (FAILED(hr))
{
printf("Failed to disable resolving externals./n");
goto clean;
}
VariantInit(&vSrc);
V_BSTR(&vSrc) = SysAllocString(L"stocks.xml");
V_VT(&vSrc) = VT_BSTR;
hr = pXMLDoc->load(vSrc, &status);
if(status!=VARIANT_TRUE)
{
hr = pXMLDoc->get_parseError(&pObjError);
hr = pObjError->get_reason(&bstr);
printf("Failed to load DOM from books.xml. %S/n",bstr);
goto clean;
}
hr = pXMLDoc->get_xml(&bstr);
printf("stocks.xml:/n%S/n", bstr);
clean:
if (bstr)
SysFreeString(bstr);
if (&vSrc)
VariantClear(&vSrc);
if (pObjError)
pObjError->Release();
if (pXMLDoc)
pXMLDoc->Release();
CoUninitialize();
return 0;
}
#include <stdio.h>
#include <msxml2.h>
// You might need to add the msxml4/sdk/(inc, lib) directories
// to the Tools->Options...->Directories in Visual Studio.
//
// You might also need to append "msxml2.lib" to the
// Project->Settings...->Link->Object/Libray Modules field.
int main(int argc, char* argv[])
{
HRESULT hr;
IXMLDOMDocument3 *pXMLDoc = NULL;
IXMLDOMParseError * pObjError = NULL;
BSTR bstr = NULL;
VARIANT_BOOL status;
VARIANT vSrc;
CoInitialize(NULL);
hr = CoCreateInstance(CLSID_DOMDocument40,
NULL,
CLSCTX_INPROC_SERVER,
IID_IXMLDOMDocument3,
(void**)&pXMLDoc);
if (FAILED(hr))
{
printf("Failed to CoCreate an instance of an XML DOM/n");
printf("Error code: %x/n", hr);
goto clean;
}
hr = pXMLDoc->put_async(VARIANT_FALSE);
if (FAILED(hr))
{
printf("Failed to set async property/n");
goto clean;
}
hr = pXMLDoc->put_validateOnParse(VARIANT_FALSE);
if (FAILED(hr))
{
printf("Failed to set validateOnParse/n");
goto clean;
}
hr = pXMLDoc->put_resolveExternals(VARIANT_FALSE);
if (FAILED(hr))
{
printf("Failed to disable resolving externals./n");
goto clean;
}
VariantInit(&vSrc);
V_BSTR(&vSrc) = SysAllocString(L"stocks.xml");
V_VT(&vSrc) = VT_BSTR;
hr = pXMLDoc->load(vSrc, &status);
if(status!=VARIANT_TRUE)
{
hr = pXMLDoc->get_parseError(&pObjError);
hr = pObjError->get_reason(&bstr);
printf("Failed to load DOM from books.xml. %S/n",bstr);
goto clean;
}
hr = pXMLDoc->get_xml(&bstr);
printf("stocks.xml:/n%S/n", bstr);
clean:
if (bstr)
SysFreeString(bstr);
if (&vSrc)
VariantClear(&vSrc);
if (pObjError)
pObjError->Release();
if (pXMLDoc)
pXMLDoc->Release();
CoUninitialize();
return 0;
}
使用goto后,指针集中释放,即使出现内存泄露也很容易发现,而且指针空间的释放都
只出现了1次-------出错易排查。
借那句经典的话吧:goto少用、慎用,但是不能禁用。
摘自 lingxiu0613的专栏