It is sometimes possible to use that style, but generally you will need nesting if you want to handle errors. I can't think of a decent embedded example that doesn't require reams of context, but here's an illustration using shared memory under Windows. Try to translate the following code snippet to the style you suggest:
errno_t get_shared_status( LPCTSTR fileName ) {
errno_t result = E_UNKNOWN;
HANDLE f = INVALID_HANDLE_VALUE;
HANDLE fMap = NULL;
LPVOID shm = NULL;
MEMORY_BASIC_INFORMATION meminfo;
SIZE_T shmLen = 0;
f = CreateFile( fileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL );
if ( f == INVALID_HANDLE_VALUE ) {
result = E_SHM_ACCESS;
log( "get_shared_status: CreateFile() failed with error %08x", GetLastError() );
goto cleanupNone;
}
fMap = CreateFileMapping( f, NULL, PAGE_READONLY, 0, 0, NULL );
if ( fMap == NULL ) {
result = E_SHM_ACCESS;
log( "get_shared_status: CreateFileMapping() failed with error %08x", GetLastError() );
goto cleanupCreateFile;
}
shm = MapViewOfFile( fMap, FILE_MAP_READ, 0, 0, 0 );
if ( shm == NULL ) {
result = E_SHM_ACCESS;
log( "get_shared_status: MapViewOfFile() failed with error %08x", GetLastError() );
goto cleanupCreateFmap;
}
shmLen = VirtualQuery( shm, &meminfo, sizeof(meminfo) );
if ( shmLen == 0 ) {
result = E_SHM_ACCESS;
log( "get_shared_status: VirtualQuery() failed with error %08x", GetLastError() );
goto cleanupMapView;
}
if ( shmLen sizeof(meminfo) ) {
result = E_SHM_ACCESS;
log( "get_shared_status: VirtualQuery() returned too few bytes" );
goto cleanupMapView;
}
if ( meminfo.RegionSize SHM_V1_SIZE ) {
result = E_SHM_ACCESS;
log( "get_shared_status: Shared memory file too small to interpret" );
goto cleanupMapView;
} //FIXME do stuff
cleanupMapView:
if ( 0 == UnmapViewOfFile( shm ) ) {
log( "get_shared_status: UnmapViewOfFile() failed with error %08x", GetLastError() );
}
shm = NULL;
cleanupFmap:
if ( 0 == CloseHandle( fMap ) ) {
log( "get_shared_status: CloseHandle(fMap) failed with error %08x", GetLastError() );
}
fMap = NULL;
cleanupCreateFile
if ( 0 == CloseHandle( f ) ) {
log( "get_shared_status: CloseHandle(f) failed with error %08x", GetLastError() );
}
f = INVALID_HANDLE_VALUE;
cleanupNone:
return result;
}
Here's the start:
f = CreateFile( fileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL );
if ( f != INVALID_HANDLE_VALUE ) {
fMap = CreateFileMapping( f, NULL, PAGE_READONLY, 0, 0, NULL );
} else {
result = E_SHM_ACCESS;
log( "get_shared_status: CreateFile() failed with error %08x", GetLastError() );
}
if ( fMap != NULL ) {
shm = MapViewOfFile( fMap, FILE_MAP_READ, 0, 0, 0 );
} else { /*
** Oops - if CreateFile() failed we end up here! */
result = E_SHM_ACCESS;
log( "get_shared_status: CreateFileMapping() failed with error %08x", GetLastError() );
}
As soon as you have a code path for exceptions you need nesting to match the error path with the code that led to it, or you will execute multiple error paths unintentionally. The 'goto' style has the same code order as try...finally would, with the 'goto' itself acting like 'throw'.