Подтвердить что ты не робот

Как обойти GCC '* ((void *) & b +4) можно использовать неинициализированные в этой функции предупреждения при использовании boost:: optional

У меня есть код, похожий на следующий:

#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;
}

При компиляции с GCC 4.7.2 с Boost 1.53, используя следующую команду:

g++ -c -O2 -Wall -DNDEBUG

Выдается следующее предупреждение:

13: 3: warning: '((void) & b +4) может использоваться неинициализированным в этой функции [-Wmaybe-uninitialized]

По-видимому, проблема с корнем лежит на GCC. См. GCC Bugzilla Кто-нибудь знает обходное решение?

4b9b3361

Ответ 1

Существует два уровня неинициализированного анализа в gcc:

  • -Wuninitialized: переменные флагов, которые, безусловно, используются неинициализированными
  • -Wmaybe-uninitialized: переменные флагов, которые потенциально используются неинициализированными

В gcc (*), -Wall включает оба уровня, хотя последний имеет ложные предупреждения, потому что анализ несовершенен. Ложные предупреждения - это чума, поэтому самый простой способ избежать их - пройти -Wno-maybe-uninitialized (после -Wall).

Если вы все еще хотите получать предупреждения, но не можете вызвать их сбой (через -Werror), вы можете их белым списком с помощью -Wno-error=maybe-uninitialized.

(*) Clang не активирует -Wmaybe-uninitialized по умолчанию именно потому, что он очень нечеткий и имеет большое количество ложных срабатываний; Я желаю, чтобы gcc следил за этим руководством.

Ответ 2

Я обнаружил, что изменение конструкции b на следующий (фактически равный) код:

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

устраняет предупреждение. Однако следующий код (который также эффективно равен):

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

не устраняет предупреждение. Это все еще немного неудовлетворительно...

Ответ 3

Имел ту же проблему с этим фрагментом кода:

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();
    }
}

Не удалось избавиться от предупреждения с ответом Павла Омты, попытался написать:

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

... без успеха.

Не хочу полностью отключать предупреждение от моего кода, поэтому я нашел альтернативное решение, которое я бы рекомендовал: отключить предупреждение локально:

        #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

Ответ 4

У меня был тип, который не был легко сконструирован, поэтому не хотелось идти по пути boost:: make_optional. Назначение автоматической переменной с использованием возврата из функции обошло эту проблему для меня. Итак, вы можете сделать:

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

auto var(Default());

Это также будет работать как однострочный лямбда, так что вы можете просто сделать:

auto var([]()->boost::optional<Foo> { return boost::none; }());