2014-09-13 61 views
4

爲什麼選擇或不選擇宏時定義錯誤/ HRESULT處理/日誌記錄?爲什麼要在HRESULT處理中避免宏?

我正在接近通過接口調用的錯誤處理類,所以我可以使用Boost共享指針在需要時隨時調用該類。 (說實話,我不知道這是不是最好的方法,但我主要想看看我能不能做到,看起來會是什麼樣子)。 即:

typedef std::shared_ptr<iErrorHandling> Error_Handler; 

Error_Handler Err_Handler(new ErrHandling); 

if (error) 
{ 
    Err_Handler->vDX_ERR(ERR_D3D_INIT_SWAP); 
} 

我開始使用與DirectX類和DirectX的需要大量的HRESULT處理我指出傾向於使用宏來避免所有的if/else語句。我碰到這樣的:

#define lengthof(rg) (sizeof(rg)/sizeof(*rg)) 

inline const char* StringFromError(char* szErr, long nSize, long nErr) 
{ 
    _ASSERTE(szErr); 
    *szErr = 0; 
    DWORD cb = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, 0, nErr, 0, szErr, nSize, 0); 
    char szUnk[] = "<unknown>"; 
    if(!cb && nSize >= lengthof(szUnk)) lstrcpyA(szErr, szUnk); 
    return szErr; 
} 

inline HRESULT TraceHR(const char* pszFile, long nLine, HRESULT hr) 
{ 
    if(FAILED(hr)) 
    { 
     char szErr[128]; 
     char sz[_MAX_PATH + lengthof(szErr) + 64]; 
     wsprintfA(sz, "%s(%d) : error 0x%x: %s\n", pszFile, nLine, hr, 
      StringFromError(szErr, lengthof(szErr), hr)); 
     OutputDebugStringA(sz); 
    } 
    return hr; 
} 

#ifdef _DEBUG 
#define TRACEHR(_hr) TraceHR(__FILE__, __LINE__, _hr) 
#else 
#define TRACEHR(_hr) _hr 
#endif 

#define HR(ex) { HRESULT _hr = ex; if(FAILED(_hr)) return TRACEHR(_hr), _hr; } 

(來源:https://www.sellsbrothers.com/writing/a_young_person.htm

雖然這看起來不錯給我我也發現了描述宏爲「邪惡」的幾個網站,他們應該很少使用。

哪種方法性能更好,爲什麼? 還有沒有發現的另一種方法?

此外;用__FILE__ __FUNC__ __LINE__來定義宏來創建錯誤日誌字符串是否合理?或者定義自己的特定錯誤並將它們列在頭文件中是否可以接受?

即:

static LPTSTR ERR_D3D_INIT_HW =  __T("cD3D::Initialize: Failed to establish hardware."); 
static LPTSTR ERR_D3D_INIT_SWAP =  __T("cD3D::Initialize: Failed to create the swap device."); 

無論哪種方法花費的時間實現哪個是更好的性能明智?

+0

Alexander Gessler絕對正確。宏不是*本質上是「邪惡的」,你的場景就是一個很好的例子,說明宏是合適的還是有用的。 – FoggyDay 2014-09-13 01:59:27

回答

4

宏並非天生就是邪惡的。但是,他們往往會使代碼難以閱讀,並且如果使用不當,可能會導致難以調試的錯誤。由於這些原因,一般的建議總是會支持較少的宏。你提出的是兩個非常特殊的情況,其中宏是好的。

  • 合併__LINE__等的日誌/跟蹤宏很常見,並且很難(不可能)在沒有宏的情況下實現相同的效果。恕我直言,他們沒有錯。
  • FAILED(hr)像宏一樣也很常見,沒有任何錯誤或難以閱讀它們。你可以使用一個函數來代替今天的編譯器,它可能會在大多數時候被內聯,但事實並非總是如此。二十年來,特別是COM/DirectX的一部分,人們習慣於解析它。