向來都是 不要用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的專欄