views:

114

answers:

2

In C++ sometimes a variable will be defined, but not used. Here's an example - a function for use with COM_INTERFACE_ENTRY_FUNC_BLIND ATL macro:

HRESULT WINAPI blindQuery( void* /*currentObject*/, REFIID iid, void** ppv, DWORD_PTR /*param*/ ) 
{
    DEBUG_LOG( __FUNCTION__ ); //DEBUG_LOG macro expands to an empty string in non-debug
    DEBUG_LOG( iid );
    iid; // <<<<<<<----silence compiler warning
    if( ppv == 0 ) {
        return E_POINTER;
    }
    *ppv = 0;
    return E_NOINTERFACE;
}

In the above example iid parameter is used with DEBUG_LOG macro that expands into an empty string in non-debug configurations. So commenting out or removing the iid variable name in the signature is not an option. When non-debug configurations are being compiled the compiler spawns a C4100: 'iid' : unreferenced formal parameter warning, so in order to silence the warning the iid; statement that is believed to be a no-op is added.

The question is the following: if we have any of the following declarations:

 CSomeType variableName; //or
 CSomeType& variableName; //or
 CSomeType* variableName;

will the following statement in C++ code:

variableName;

be a no-op at all times independent of what CSomeType is?

+11  A: 

Yes, but you'll likely get another warning.

The standard way of doing this is: (void)iid;.


Very technically, this could still load iid into a register and do nothing. Granted that's extremely stupid on the compilers part (I doubt any would ever do that), but it does bring up another interesting question: Can you take an expression and completely ignore it?

That is, what we have now is this:

#define USE(x) (void)(x)

// use iid in an expression to get rid of warning, but have no observable effect
USE(iid); 

// hm, result of expression is gone but expression is still evaluated
USE(std::cout << "hmmm" << std::endl);

This is close to a solution:

// sizeof doesn't evaluate the expression
#define USE(x) (void)(sizeof(x))

But fails with:

void foo();

// oops, cannot take sizeof void
USE(foo());

The solution is to simply:

// use expression as sub-expression,
// then make type of full expression int, discard result
#define USE(x) (void)(sizeof((x), 0))

Which guarantees no operation.

GMan
Though I agree, this doesn't mean the expression has to become a no-op. The compiler could, if it so desired, load the value into a register and then ignore it. While this would be silly it isn't unfathomable that an optimizing compiler leaves bits around sometimes.
edA-qa mort-ora-y
@eda: It is required to do nothing. Please see the quote [here](http://stackoverflow.com/questions/4031228/why-is-operator-void-not-invoked-with-cast-syntax/4031487#4031487).
GMan
No, the expression "value" is discarded. Loading the value into a register, or otherwise indicating its existence to the CPU would not violate that rule. As far the language is concerned it had no discernable side-effects.
edA-qa mort-ora-y
@edA: Alright. How's that?
GMan
@edA: but it would be a waste of time to do so, and the compiler wouldn't merely have to avoid optimizing, it'd have to actively de-optimize the code.
jalf
I'm not saying a good optimizer would do this, nor do I know a case where it does, but I'm saying the author of the optimizer may have made a mistake -- it happens. So if it is absolutely critical that no code is generated, then it should not be present at all.
edA-qa mort-ora-y
@edA: What of the last `USE` definition?
GMan
Again, I don't see anything in the standard that would prevent 0 from being evaluated. But more importantly the (x) will be evaluated in this case, not what we want. To solve the original problem we should probably put the original parameter in a macro and attach the "unused" parameter (this works for GCC, other compilers must have an alternative)...
edA-qa mort-ora-y
@edA: Huh? The whole thing is inside of `sizeof`, which does not evaluate its arguments. Granted, I guess it could conceivably load the constant result into a register and ignore it again.
GMan
You are correct. sizeof should not evaluate the expression -- it resolves only into a constant time variable.
edA-qa mort-ora-y
+2  A: 

Well, it's not really possible to say with 100% certainty without looking at the compiler's source code, but I would be very surprised if this ever generated any code in modern compilers.

At the end of the day, if you're worried about any particular instance then you are always free to look at the generated assembly code.

Peter Alexander