gotoプログラミングのすゝめ

ある人が作っていたBREWのアプリのソースを、自分が引き継いだ訳なんだけれども、これがめちゃめちゃ凄い。
こんな感じになってる。

int foo( CHoge* pMe , char* pFileName ){
    int ret;
    int ret2;
    IFileMgr* pIFileMgr;
    IFile* pIFile;
    FileInfo fileInfo;
    char* pData;

    ret2 = ISHELL_CreateInstance( pMe->a.m_pIShell ,
                                  AEECLSID_FILEMGR ,
                                  (void **)(&pIFileMgr) );
    if( ret2 != SUCCESS ){
        ret = EFAILED;
        return ret;
    }

    pIFile = IFILEMGR_OpenFile( pIFileMgr ,
                                pFileName ,
                                _OFM_READ );
    if( pIFile == NULL ){
        IFILEMGR_Release( pIFileMgr );
        pIFileMgr = NULL;
        ret = EFAILED;
        return ret;
    }

    ret2 = IFILE_GetInfo( pIFile , &fileInfo );
    if( ret2 != SUCCESS ){
        IFILE_Release( pIFile );
        pIFile = NULL;
        IFILEMGR_Release( pIFileMgr );
        pIFileMgr = NULL;
        ret = EFAILED;
        return ret;
    }

    size = fileInfo.dwSize;

    pData = MALLOC( size + 1 );
    if( pData == NULL ){
        IFILE_Release( pIFile );
        pIFile = NULL;
        IFILEMGR_Release( pIFileMgr );
        pIFileMgr = NULL;
        ret = EFAILED;
        return ret;
    }

    ret2 = IFILE_Read( pIFile , pData , size );
    if( (uint32)ret2 != size ){
        FREE( pData );
        pData = NULL;
        IFILE_Release( pIFile );
        pIFile = NULL;
        IFILEMGR_Release( pIFileMgr );
        pIFileMgr = NULL;
        ret = EFAILED;
        return ret;
    }

    // なんかの処理

    ret = SUCCESS;

    FREE( pData );
    pData = NULL;
    IFILE_Release( pIFile );
    pIFile = NULL;
    IFILEMGR_Release( pIFileMgr );
    pIFileMgr = NULL;

    return ret;
}

……まじで勘弁して(;´Д`)
失敗するたびに、使用しているリソースを全て解放してからreturnしてます。
おかげで似たような処理が大量に埋め込まれてます。


で、ここを編集しないといけなくなったんだけど、こんなの見てられるか!
ってことで修正。

#define SAFE_SHELL_RELEASE( name , p ) \
    if( p != NULL ){ \
        name##_Release( p ); \
        p = NULL; \
    }

#define SAFE_RELEASE( p ) \
    if( p != NULL ){ \
        FREE( p ); \
        p = NULL; \
    }

int foo( CHoge* pMe , char* pFileName ){
    int ret;
    IFileMgr* pIFileMgr;
    IFile* pIFile;
    FileInfo fileInfo;
    char* pData;

    int ret2;
    int size;

    ret = EFAILED;
    pIFileMgr = NULL;
    pIFile = NULL;
    pData = NULL;

    ret2 = ISHELL_CreateInstance( pMe->a.m_pIShell ,
                                  AEECLSID_FILEMGR ,
                                  (void**)(&pIFileMgr) );
    if( ret2 != SUCCESS ) goto release;

    pIFile = IFILEMGR_OpenFile( pIFileMgr ,
                                pFileName ,
                                _OFM_READ );
    if( pIFile == NULL ) goto release;

    ret2 = IFILE_GetInfo( pIFile , &fileInfo );
    if( ret2 != SUCCESS ) goto release;

    size = fileInfo.dwSize;

    pData = MALLOC( size + 1 );
    if( pData == NULL ) goto release;

    ret2 = IFILE_Read( pIFile , pData , size );
    if( (uint32)ret2 != size ) goto release;

    // なんかの処理

    ret = SUCCESS;

release:;
    SAFE_RELEASE( pData );
    SAFE_SHELL_RELEASE( IFILE , pIFile );
    SAFE_SHELL_RELEASE( IFILEMGR , pIFileMgr );

    return ret;
}

はふー。落ち着いた。
gotoってやっぱり便利ですねヽ(´ー`)ノ