I hope I do not get a religious argument started, but here goes...

When I program, I try to write code that is easy to read, and easy to use. This should make it easy to maintain, and reuse by others (copy and paste).

The most generic way I know to control flow through a function is with goto statements (while keeping the function easy to read).

Consider the following:

Code:
LONG CAESEncRegKey::ReadData(BYTE **pcbData, DWORD *pdwSize) const
Code:
{
	LONG	lResult = ERROR_SUCCESS;
	HKEY	hKey	= NULL;
 
	ASSERT( NULL != pcbData && NULL != pdwSize );
 
	// Sanity Check
	if( NULL == pcbData || NULL == pdwSize ) {		
		lResult = ERROR_INVALID_PARAMETER;
		goto FINISHED;
	}
 
	// Open the Key
	lResult = RegOpenKeyEx( _hKey, _szSubKey, 0, KEY_READ, &hKey );
 
	// Sanity Check
	if( ERROR_SUCCESS != lResult ) { goto FINISHED; }
 
	// Query for needed buffer size
	lResult = RegQueryValueEx( hKey, _szValueName, 0, NULL, NULL, pdwSize );
 
	if( ERROR_SUCCESS != lResult ) { goto FINISHED; }
 
	// Allocate a buffer
	*pcbData = new BYTE[ *pdwSize + sizeof(TCHAR) ];
 
	// Sanity Check
	if( NULL == *pcbData ) {
		lResult = ERROR_NOT_ENOUGH_MEMORY;
		goto FINISHED;
	}
 
	// Query for the actual value
	lResult = RegQueryValueEx( hKey, _szValueName, 0, NULL, *pcbData, pdwSize );
 
FINISHED:
 
	if( NULL != hKey ) { RegCloseKey( hKey ); }
 
	return lResult;
 
}


If using it/then/else, the code could be nested four levels. I don’t think this is easy to read (again, my humble opinion).

Another option would be to use try/throw/catch. However, this option would force the program to use Exception handling, which is something a programmer may not want to do. For example, eVC 4.0 does not implement exception handling, so one could write a program/class/function that is basically useless.

With that said, the following usess Exceptions:

Code:
LONG CAESEncRegKey::ReadData(BYTE **pcbData, DWORD *pdwSize) const
Code:
{
	LONG	lResult = ERROR_SUCCESS;
	HKEY	hKey	= NULL;
 
	try {
 
		// Sanity Check
		if( NULL == pcbData || NULL == pdwSize ) {		
			throw (LONG) ERROR_INVALID_PARAMETER;
		}
 
		// Open the Key
		lResult = RegOpenKeyEx( _hKey, _szSubKey, 0, KEY_READ, &hKey );
 
		// Sanity Check
		if( ERROR_SUCCESS != lResult ) {
			throw (LONG) lResult;
		}
 
		// Query for needed buffer size
		lResult = RegQueryValueEx( hKey, _szValueName, 0, NULL, NULL, pdwSize );
 
		if( ERROR_SUCCESS != lResult ) {		 
			throw (LONG) lResult;
		}
 
		// Allocate a buffer
		*pcbData = new BYTE[ *pdwSize + sizeof(TCHAR) ];
 
		// Sanity Check
		if( NULL == *pcbData ) {
			throw (LONG) ERROR_NOT_ENOUGH_MEMORY;
		}
 
		// Query for the actual value
		lResult = RegQueryValueEx( hKey, _szValueName, 0, NULL, *pcbData, pdwSize );
	}
 
	catch ( LONG lr ) {
 
		lResult = lr;
	}
 
	catch ( ... ) {
 
		lResult = ERROR_GEN_FAILURE;
	}
 
	if( NULL != hKey ) { RegCloseKey( hKey ); }
 
	return lResult;
}



I suppose my question is, what is the preferred method?


Jeff