C++ Gotcha

If you don’t care a bit about programming, then skip this.

Stephen Dewhurst wrote an excellent book titled “C++ Gotchas”. I’ve read it twice already, and was just re-looking through a few things again last night. One of them actually hit me today, which I find quite ironic.

I have a small piece of code that looks like this:

try {
return linearConversion( getRawValue(device), d->devicedata[device].cal );
} catch (Gina::InvalidDevice &) {
return getValue(device);
}

The premise of the code is to attempt to perform a conversion on a raw data value. If however, the raw data value doesn’t exist, then we return a regular data value instead.

This line is the culprit:

return linearConversion( getRawValue(device), d->devicedata[device].cal );

When the program executes getRawValue(device), it attempts to first determine if the device is valid. It does this by looking up to see if it exists in the devicedata list. If it doesn’t exist, this thing throws an exception - otherwise, it runs the linearConversion function and passes in the calibration (also stored in devicedata).

But here’s what interesting. C++ has no requirement on the order of evaluation for function arguments. For example:

doSomethingFancy( calculateA(), calculateB())

In this case, you cannot know whether calculateA or calculateB will be executed first. Granted, they have to both be executed before you can run doSomethingFancy(), but the order in which they are executed is picked by the compiler. It doesn’t happen left to right.

That was what was biting me before:

return linearConversion( getRawValue(device), d->devicedata[device].cal );

I was using getRawValue() as a determination of whether or not we could continue; however, in some cases d->devicedata[device].cal was being executed first. d->devicedata[device] didn’t already exist in the list, and my getRawValue() checks specifically for it, but since it was being executed first C++ was adding it to the list - causing getRawValue() to not fail anymore. Yikes.

6 Responses to “C++ Gotcha”

  1. corbin Says:

    note to self: when caleb says skip it, it’s probably worth skipping

  2. robbat2 Says:

    And if you use OpenMP-type stuff, you can end up with cases that calculateA() and calculateB() both run at the SAME time.

  3. Frank Birbacher Says:

    The C language does not specify the evaluation order either. BTW, exceptions are to be caught via *const* reference.

  4. Henry Miller Says:

    Thanks for the reminder. I knew this, but like you I don’t always remember it.

    I just wish it was subtle things like this that were the cause of my of my errors…

  5. anonymous coward Says:

    For one there is no such thing as a const reference. It’s a reference-to-const. If you think it makes no difference then try talking about pointers.

  6. michael Says:

    is this really a gotcha? it seems like careless programming to me.