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

У меня есть код, подобный следующему:

#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: предупреждение: ‘((Пустота)& b +4) ’может использоваться неинициализированным в этой функции [-Wmaybe-uninitialized]

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

23

Решение

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

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

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

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

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

23

Другие решения

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

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

устраняет предупреждение Тем не менее, следующий код (который также фактически равен):

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

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

10

Была такая же проблема с этим фрагментом кода:

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
5

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

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

auto var(Default());

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

auto var([]()->boost::optional<Foo> { return boost::none; }());
2
По вопросам рекламы [email protected]