Resource Cleanup Dynamically allocated memory / resources must be appropriately cleaned up before you exit from a function to avoid memory / resource leaks. Proper resource cleanup solution is particularly important when an error occurs in the middle of the function. Here are five commonly seen patterns of code to clean up resources in a function. Pattern Example Analysis goto HANDLE hToken = NULL; If you are absolutely sure that the PVOID pMem = NULL; Cleanup code does not an exception, "goto Cleanup" should be the best if (!OpenProcessToken(GetCurrentProcess(), choice. It is faster than TOKEN_QUERY, &hToken)) { "__try/__finally", is easier to ReportError(GetLastError()); implement than "Early return with goto Cleanup; RAII wrapper", and is portal to C. } pMem = LocalAlloc(LPTR, 10); if (pMem == NULL) { ReportError(GetLastError()); goto Cleanup; } ... Cleanup: if (hToken) { CloseHandle(hToken); hToken = NULL; } if (pMem) { LocalFree(pMem); pMem = NULL; } __try / HANDLE hToken = NULL; __try/__finally is not portable to PVOID pMem = NULL; __finally other systems, hamstrings the optimizer, and is surprisingly more __try expensive than goto and early return. { if (!OpenProcessToken(GetCurrentProcess(), __try / __finally inhibits a large set of TOKEN_QUERY, &hToken)) optimizations because the compiler { must assume that something bad can ReportError(GetLastError()); __leave; happen at any time (in the middle of } an expression, or inside a function you called). In contrast, "goto" lets pMem = LocalAlloc(LPTR, 10); if (pMem == NULL) the compiler assume that bad things { happen only when you do a "goto". ReportError(GetLastError()); __leave; } ... } __finally { if (hToken) {
Resource Cleanup Dynamically allocated memory / resources must be appropriately cleaned up before you exit from a function to avoid memory / resource leaks. Proper resource cleanup solution is particularly important when an error occurs in the middle of the function. Here are five commonly seen patterns of code to clean up resources in a function. Pattern Example Analysis goto Cleanup HANDLE hToken = NULL; PVOID pMem = NULL; if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) { ReportError(GetLastError()); goto Cleanup; } pMem = LocalAlloc(LPTR, 10); if (pMem == NULL) { ReportError(GetLastError()); goto Cleanup; } ... Cleanup: if (hToken) { CloseHandle(hToken); hToken = NULL; } if (pMem) { LocalFree(pMem); pMem = NULL; } If you are absolutely sure that the code does not an exception, "goto Cleanup" should be the best choice. It is faster than "__try/__finally", is easier to implement than "Early return with RAII wrapper", and is portal to C. __try / __finally HANDLE hToken = NULL; PVOID pMem = NULL; __try { if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) { ReportError(GetLastError()); __leave; } pMem = LocalAlloc(LPTR, 10); if (pMem == NULL) { ReportError(GetLastError()); __leave; } ... } __finally { if (hToken) { __try/__finally is not portable to other systems, hamstrings the optimizer, and is surprisingly more expensive than goto and early return. __try / __finally inhibits a large set of optimizations because the compiler must assume that something bad can happen at any time (in the middle of an expression, or inside a function you called). In contrast, "goto" lets the compiler assume that bad things happen only when you do a "goto".