2014-09-13 59 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的一部分,人们习惯于解析它。