35

我有类似于以下的代码:

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

使用 Boost 1.53 编译 GCC 4.7.2 时,使用以下命令:

g++ -c -O2 -Wall -DNDEBUG

发出以下警告:

13:3:警告:'<em>((void)& b +4)' 可能在此函数中未初始化 [-Wmaybe-uninitialized]

显然,根本问题在于 GCC。请参阅GCC Bugzilla 有人知道解决方法吗?

4

4 回答 4

36

gcc中有两个级别的未初始化分析:

  • -Wuninitialized: 标记肯定使用未初始化的变量
  • -Wmaybe-uninitialized: 标记可能使用未初始化的变量

在 gcc (*) 中,-Wall打开两个级别,即使后者有虚假警告,因为分析不完善。虚假警告是一种瘟疫,因此避免它们的最简单方法是通过-Wno-maybe-uninitialized(在 之后-Wall)。

如果您仍然想要警告,但不让它们导致构建失败(通过-Werror),您可以使用 将它们列入白名单-Wno-error=maybe-uninitialized

(*) Clang 默认不会激活-Wmaybe-uninitialized,因为它非常不精确并且有很多误报;我希望 gcc 也遵循这个准则。

于 2014-02-13T14:07:28.700 回答
19

我发现将 b 的构造更改为以下(实际上相等)代码:

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

消除警告。但是,以下代码(实际上也是等效的):

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

不会消除警告。还是有点不满意。。。

于 2014-02-13T13:09:54.823 回答
5

这段代码有同样的问题:

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

无法摆脱 Paul Omta 回答的警告,试图写:

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
于 2016-10-07T10:42:56.557 回答
3

我有一个不容易构造的类型,所以不想走 boost::make_optional 路线。使用函数的返回值分配一个自动变量为我解决了这个问题。所以你可以这样做:

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

auto var(Default());

这也将作为单行 lambda 工作,因此您可以这样做:

auto var([]()->boost::optional<Foo> { return boost::none; }());
于 2017-03-10T12:15:34.280 回答