I am using some Qt code that adds a VERIFY macro that looks something like this:
#define VERIFY(cond) \
{ \
bool ok = cond; \
Q_ASSERT(ok); \
}
The cod开发者_如何学JAVAe can then use it whilst being certain the condition is actually evaluated, e.g.:
Q_ASSERT(callSomeFunction()); // callSomeFunction not evaluated in release builds!
VERIFY(callSomeFunction()); // callSomeFunction is always evaluated
Disliking macros, I would instead like to turn this into an inline function:
inline VERIFY(bool condition)
{
Q_ASSERT(condition);
}
However, in release builds I am worried that the compiler would optimise out all calls to this function (as Q_ASSERT
wouldn't actually do anything.) I am I worrying unnecessarily or is this likely depending on the optimisation flags/compiler/etc.? I guess I could change it to:
inline VERIFY(bool condition)
{
condition;
Q_ASSERT(condition);
}
But, again, the compiler may be clever enough to ignore the call.
Is this inline alternative safe for both debug and release builds?
Even if the compiler optimises out your inline VERIFY function then that does not imply it will not call the function that is generating the bool argument.
The reason Q_ASSERT does not call the function passed to it in release builds is that it is a macro which simply doesn't substitute the function call in at all so there is nothing to optimise away.
In case of inline functions there's no guarantee the function arguments are not evaluated.
Since their evaluation might have or not have side effects you will at very best have hard times maintaining the code - in cases where there is a side effect evaluation will surely take place, in other cases it will take or not take place at the discretion of the compiler. This leaves you with a program that behaves in loosely controlled manner.
So even with your dislike towards macros you should make an informed decision. Either you use a macro and then the whole construct is eliminated by the preprocessor and the parameters are not evaluated, or you use an inline function and then the compiler decides for you.
The optimiser will not remove code which has side effects, otherwise optimising the program would change the way it works! In this case, the function argument will always be evaluated if it has side effects (eg. printing something to the console), even if the function it is passed to is completely eliminated.
Imagine this code:
int x = Return5();
int y = PrintToConsoleAndReturn5();
// x and y never used again
The optimiser can omit the call to Return5()
(assuming it consists simply of return 5;
) since it has no side effects, therefore the entire line will emit no operations. However, the optimiser cannot omit the call to PrintToConsoleAndReturn5()
(but it may inline it), because it has side effects. It may omit returning the integer 5 and storing it in to y
, because that code has no side effects. In short the theory is the behavior of the program should be identical either optimised or unoptimised, so you should be OK in your original question.
During optimizations, a compiler must still respect the observable effects of the code at hand. That means it must keep callSomeFunction()
if calling that is observable. (There are specific exceptions that apply to copying objects around, where the elimination of copies could be noticed - irrelevant here).
However, optimizations don't matter for Q_ASSERT(callSomeFunction());
in release mode. There's simply nothing left to optimize when the preprocessor is done, and the Q_ASSERT macro expanded!
精彩评论