Как обойти 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
Кто-нибудь знает обходное решение?
Ответы
Ответ 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; }());