37

I have code similar to the following:

#include <boost/optional.hpp>

::boost::optional<int> getitem();

int go(int nr)
{
  boost::optional<int> a = getitem();
  boost::optional<int> b;

  if (nr > 0)
    b = nr;

  if (a != b)
    return 1;

  return 0;
}

When compiling with GCC 4.7.2 with Boost 1.53, using the following command:

g++ -c -O2 -Wall -DNDEBUG

The following warning is issued:

13:3: warning: ‘((void)& b +4)’ may be used uninitialized in this function [-Wmaybe-uninitialized]

Apparently, the root problem lies with GCC. See GCC Bugzilla Does anyone know a workaround?

Paul Omta
  • 1,703
  • 1
  • 12
  • 17
  • If the constructor of `b` doesn't initialize all that is inside of it, then by all means, `b` in the expression `a != b` may be uninitialized. What if you actually initialize `b`? Do you still get a warning? – Shahbaz Feb 13 '14 at 13:15
  • 1
    @Shahbaz: The constructor of 'b' creates an optional where the value doesn't exist. This is valid behavior for an optional. 'a != b' Should be true if both optionals are uninitialized. So this should be valid code. Initializing 'b' with a value does eliminate the warning, but that's not an option since it changes the behavior of the code. What 'getitem()' returns may be an uninitialized optional. – Paul Omta Feb 19 '14 at 07:18

4 Answers4

37

There are two levels of uninitialized analysis in gcc:

  • -Wuninitialized: flags variables that are certainly used uninitialized
  • -Wmaybe-uninitialized: flags variables that are potentially used uninitialized

In gcc (*), -Wall turns on both levels even though the latter has spurious warnings because the analysis is imperfect. Spurious warnings are a plague, so the simplest way to avoid them is to pass -Wno-maybe-uninitialized (after -Wall).

If you still want the warnings, but not have them cause build failure (through -Werror) you can white list them using -Wno-error=maybe-uninitialized.

(*) Clang does not activate -Wmaybe-uninitialized by default precisely because it's very imprecise and has a good number of false positives; I wish gcc followed this guideline too.

Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
20

I have found that changing the construction of b into the following (effectively equal) code:

auto b = boost::make_optional(false,0);

eliminates the warning. However, the following code (which is also effectively equal):

boost::optional<int> b(false,0);

does not eliminate the warning. It's still a little unsatisfactory...

Paul Omta
  • 1,703
  • 1
  • 12
  • 17
  • how about `auto b = boost::make_optional(false, 0);`? – rubenvb Feb 13 '14 at 13:12
  • @rubenvb: using auto, I consider that to be better style. I'll change the answer. – Paul Omta Feb 19 '14 at 07:20
  • I had the exact same warning, but this solution didn't help me. I had to get rid of the `optional` altogether (which I fortunately could in my situation). – Angew is no longer proud of SO Oct 06 '16 at 16:22
  • Somehow this causes gcc to set the TREE_NO_WARNING internal flag on this variable. The warning is not unlikely to come back in a future version, this is more fragile than the pragma. – Marc Glisse Jun 05 '18 at 22:04
  • You're a life saver! :) Strangely enough, this is an issue only with gcc 4.9.2 and it works perfectly fine on 4.9.3. Even more - it works fine on 4.9.2 in debug builds, but fails on release builds. – Kiril Kirov Mar 10 '21 at 16:19
6

Had the same issue with this piece of code:

void MyClass::func( bool repaint, bool cond )
{
    boost::optional<int> old = m_sizeLimit; // m_sizeLimit is a boost::optional<int> class attribute

    if ( cond )
        m_sizeLimit = 60;
    else
        m_sizeLimit.reset();

    if ( repaint )
    {
        if ( old != m_sizeLimit ) // warning here
            doSomething();
    }
}

Could not get rid of the warning with Paul Omta answer, tried to write:

boost::optional<int> old;
if ( m_sizeLimit )
    old = boost::make_optional<int>(true, m_sizeLimit.value());
else
    old = boost::make_optional<int>(false, 0);

...with no success.

Did not want to completely disable the warning from my code, so I found an alternative solution I would recommend: disable the warning locally:

        #ifdef SDE_MOBILE
        #pragma GCC diagnostic push
        #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
        #endif

        if ( old != m_sizeLimit ) // warning here
            doSomething();

        #ifdef SDE_MOBILE
        #pragma GCC diagnostic pop
        #endif
jpo38
  • 20,821
  • 10
  • 70
  • 151
  • 1
    Thanks for the solution. Ran into the problem with gcc 4.9.2, and your `#pragma`-based solution worked and was the best option for me. – mindriot May 12 '17 at 20:48
3

I had a type which wasn't easily constructed so didn't want to go the boost::make_optional route. Assigning an auto variable using the return from a function got around this problem for me. So you can do:

boost::optional<Foo> Default()
{
    return boost::none;
}

auto var(Default());

This will also work as a one line lambda so you can just do:

auto var([]()->boost::optional<Foo> { return boost::none; }());
Harry
  • 119
  • 1
  • 3