У меня есть код, подобный следующему:
#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
Кто-нибудь знает обходной путь?
В gcc есть два уровня неинициализированного анализа:
-Wuninitialized
: флаги переменных, которые конечно используется неинициализированный-Wmaybe-uninitialized
: флаги переменных, которые потенциально используется неинициализированныйВ gcc (*), -Wall
включает оба уровня, хотя последний имеет ложные предупреждения, потому что анализ несовершенен. Ложные предупреждения — это чума, поэтому самый простой способ их избежать — пройти -Wno-maybe-uninitialized
(после -Wall
).
Если вы все еще хотите предупреждения, но не хотите их вызывать сбой сборки (через -Werror
) вы можете белый список их с помощью -Wno-error=maybe-uninitialized
,
(*) Clang не активируется -Wmaybe-uninitialized
по умолчанию именно потому, что он очень неточный и содержит большое количество ложных срабатываний; Я бы хотел, чтобы gcc тоже следовал этому руководству.
Я обнаружил, что изменение конструкции b в следующий (эффективно равный) код:
auto b = boost::make_optional(false,0);
устраняет предупреждение Тем не менее, следующий код (который также фактически равен):
boost::optional<int> b(false,0);
не устраняет предупреждение.
Это все еще немного неудовлетворительно …
Была такая же проблема с этим фрагментом кода:
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
У меня был тип, который не был легко сконструирован, поэтому я не хотел идти по пути boost :: make_optional. Назначение автоматической переменной с использованием возврата из функции обошло эту проблему для меня. Так что вы можете сделать:
boost::optional<Foo> Default()
{
return boost::none;
}
auto var(Default());
Это также будет работать как одна строка лямбда, так что вы можете просто сделать:
auto var([]()->boost::optional<Foo> { return boost::none; }());