Search code examples
visual-c++mfccode-analysis

What is the best alternative to using ENSURE to avoid code analysis warnings?


Example:

ENSURE(strTitle.LoadString(AFX_IDS_APP_TITLE));
ENSURE(strMainInstruction.LoadString(IDS_STR_SUBMIT_STATS_MAIN_TEXT));
ENSURE(strContent.LoadString(IDS_STR_SUBMIT_STATS_CONTENT_TEXT));
ENSURE(strAdditional.LoadString(IDS_STR_SUBMIT_STATS_ADDITIONAL_TEXT));
ENSURE(strFooter.LoadString(IDS_STR_TASK_DIALOG_FOOTER));
ENSURE(strVerification.LoadString(IDS_STR_SUBMIT_STATS_VERIFICATION_TEXT));
ENSURE(strExpand.LoadString(IDS_STR_FIND_OUT_MORE));
ENSURE(strCollapse.LoadString(IDS_STR_COLLAPSE));

Definition:

#define ENSURE(cond) ENSURE_THROW(cond, ::AfxThrowInvalidArgException() )

It is a Microsoft macro, although I can't see it documented. I started using it when I noticed it being used in Microsoft SDK code. Annoyingly it triggers code analysis:

Warning C26496: The variable '__afx_condVal' does not change after construction, mark it as const (con.4).

I did raise it with Microsoft. The underlying macro ENSURE_THROW:

#define ENSURE_THROW(cond, exception)   \
    do { int __afx_condVal=!!(cond); ASSERT(__afx_condVal); if (!(__afx_condVal)){exception;} } __pragma(warning(suppress:4127)) while (false)

... it only needs the word const to resolve it.


Is there an alternative call I can make because I understand that ASSERT only works in DEBUG build.


Solution

  • You could redefine ENSURE_THROW and put this into your stdafx.h:

    #undef ENSURE_THROW
    #define ENSURE_THROW(cond, exception)   \
        do { const int __afx_condVal=!!(cond); ASSERT(__afx_condVal); \
        if (!(__afx_condVal)){exception;} } while (false)
    

    It's identical to the original MS definiton in afx.h, but with the const added.

    This could break in future versions of MFC, although it is unlikely that MS will ever change this.

    A cleaner way would be excluding certain header files from the analysis, but this depends on your tool.

    Be aware that ENSURE and ASSERT are very different things:

    • ASSERT(x) : in debug builds it will stop the program execution with a message if x is false, in release builds it's a NOP, x won't even be evaluated
    • ENSURE(x) : x will be evaluated and if it's false an exception will be thrown. In debug builds a diagnostic dialog is shown before the exception is thrown.