Search:

PmWiki

pmwiki.org

edit SideBar

Main / Auto

Convenience Gone Wrong: A C++ auto Story

20 February 2026 by Phillip Johnston

An insidious C++ error related to my use of auto ended up driving me nuts for hours this week.

I was revisiting a driver I wrote, and I noticed that my latest version was giving me consistent bogus readings. I checked an older version, which was providing correct values. I skimmed the code but couldn’t find any obvious functional differences, so I started looking at the I2C traffic. Even more maddening, the raw bus traffic was identical!

I won’t bury the lead too much: the root cause of my problem was that I missed an & on an auto variable declaration. This happened in a function that reads calibration data from the sensor and stores it in a struct in memory. The calibration data is then used when converting the raw sensor data. The problem is that auto cal = inst.calibration created a local copy of the struct. The register reads populated the local copy, which is destructed when exiting the function, leaving the actual calibration data empty.

static void readCompensationData(BME280& inst)
{
    // Make a convenience alias to save some typing
    auto cal = inst.calibration;  // <--- BUG: this is a COPY!
    /*
      ... reads all calibration values into the local copy
    */

    // End of function, the local `cal` is destructed
}

C++

The solution was to simply make it a reference by declaring as auto &.

static void readCompensationData(BME280& inst)
{
-   auto cal = inst.calibration;
+   auto& cal = inst.calibration;

Diff

Definitely user error here rather than a language failure. Nonetheless, hours were spent finding that single missing character.

The frustrating part to me was that I know auto behaves this way: it’s simply mirroring the type definition, and declares another struct rather than a reference. I’m also used to looking out for this in other contexts, as it’s a common mistake you can make when working with range-based for loops in C++.

Yet, it ended up being such an insidious error:

  • auto silently made a copy, nothing warned me that my intent here was not being executed
  • The code reads perfectly fine when you’re looking over it
  • The hardware interaction was suspect, but ended up being correct
  • I’m reflecting on how the whole reason I ended up in this situation was “convenience.” Had I specified the type name explicitly rather than using auto, I would have likely caught the copy right away rather than having my brain gloss over it. Ultimately I could have just lived with inst.calibration rather than seeking an easier way. Based on all the time I spent debugging this shortened alias, I could have handwritten inst.calibration on a whiteboard hundreds of times.

Now I’m wondering just how many hours attempts at convenience or expedience have cost me.


Page last modified on March 17, 2026, at 02:29 PM