【问题标题】:Why does gcc gives me maybe-uninitialized warning for deque::insert with a filtered range为什么 gcc 会给我带有过滤范围的 deque::insert 可能未初始化的警告
【发布时间】:2020-05-16 13:40:50
【问题描述】:

为什么在使用-O2 和-DNDEBUG 编译时,gcc 会给我带有过滤范围的deque::insert 可能未初始化的警告

#include <deque>
#include <vector>
#include <boost/range/adaptor/filtered.hpp>

auto foo(){
    std::deque<int> d{3,4};
    std::vector<int> v{0,2};
    auto b = 1;
    using boost::adaptors::filtered;
    auto r = v | filtered([&b](auto i){return i>b;});

    d.insert(std::end(d),r.begin(),r.end());
    return d;
}

编译器 gcc 9.2,标志 -std=c++2a -O2 -Wall -Werror -DNDEBUG

这是警告:

<source>: In member function 'void std::deque<_Tp, <source>: In member function 'void std::deque<_Tp, _Alloc>::_M_insert_aux(std::deque<_Tp, _Alloc>::iterator, _ForwardIterator, _ForwardIterator, std::deque<_Tp, _Alloc>::size_type) [with _ForwardIterator = boost::iterators::filter_iterator<boost::range_detail::default_constructible_unary_fn_wrapper<foo()::<lambda(auto:1)>, bool>, __gnu_cxx::__normal_iterator<int*, std::vector<int> > >; _Tp = int; _Alloc = std::allocator<int>]':

<source>:10:48: error: '*((void*)& __mid +16)' may be used uninitialized in this function [-Werror=maybe-uninitialized]

   10 |     auto r = v | filtered([&b](auto i){return i>b;});

      |                                               ~^~

In file included from /opt/compiler-explorer/gcc-9.2.0/include/c++/9.2.0/deque:69,

                 from <source>:1:

/opt/compiler-explorer/gcc-9.2.0/include/c++/9.2.0/bits/deque.tcc:793:24: note: '*((void*)& __mid +16)' was declared here

  793 |       _ForwardIterator __mid = __first;

      |                        ^~~~~

<source>:10:48: error: '*((void*)& __mid +16)' may be used uninitialized in this function [-Werror=maybe-uninitialized]

   10 |     auto r = v | filtered([&b](auto i){return i>b;});

      |   

如果b被值捕获,则警告消失。

https://godbolt.org/z/8Tbfgf

【问题讨论】:

  • 只是一个编译器错误。请注意,gcc 8 不再发出警告。
  • +1 表示编译器错误。如果您将 lambda 更改为仅通过引用 [&amp;] 捕获所有内容,则错误也会消失,因此对于命名捕获的初始化状态会感到困惑......
  • 请注意,在此警告中,“未初始化”也可以表示“在其销毁之后”。
  • 这个警告一直(仍然)非常脆弱。特别是,它经常触发编译器没有注意到的死代码,死代码很容易是编译器本身通过内联、展开等产生的东西。

标签: c++ gcc boost c++14 deque


【解决方案1】:

您正在通过引用捕获编译时间常数。

filtered([](auto i){return i>b;})

那是legal,因为const auto b = 1 是编译时常量,您可以在不引用的情况下使用。

编译器对按名称捕获的对编译时常量的未使用引用感到困惑。它可能会优化所述捕获,因为可以跳过从未使用过的引用。这会给您留下未初始化的捕获 b,其他代码会将其与同名的编译时值混淆,并且您会收到警告。

这显然是一个编译器错误。相反,它可能应该警告您:

variable captured but unused

或类似的东西。

【讨论】:

  • @ZhengQu const auto b = 1 是一个编译时间常数。
  • @ZhengQu 在肯定地表达之前考虑在反驳某人之前怀疑自己。 ;) 由于遗留原因,它可能只是一个编译时间常数,但它确实是一个编译时间常数。 C++ 有一些怪癖。
  • @Yakk-AdamNevraumont 我很抱歉。我一定是误会了什么。你能告诉我compile time constant的定义是什么吗?一些文档链接也将不胜感激。
  • @ZhengQu “可用于常量表达式”的定义在这里:eel.is/c++draft/expr.const#3.
  • 如果 b 不是常量表达式 godbolt.org/z/6CWUYU,我会收到相同的警告
猜你喜欢
  • 1970-01-01
  • 2016-03-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-16
  • 1970-01-01
  • 2012-07-18
  • 2023-03-12
相关资源
最近更新 更多