C++ 为什么std::push_heap即使不涉及签名类型也会生成-Wstrict overflow=3警告?

C++ 为什么std::push_heap即使不涉及签名类型也会生成-Wstrict overflow=3警告?,c++,g++,warnings,c++-standard-library,signed-overflow,C++,G++,Warnings,C++ Standard Library,Signed Overflow,根据第3级的文件: 还警告[s]其他简化比较的情况。例如:x+1>1简化为x>0 如果将优化设置为-O2且高于但不低于,则如下所示的MWE在3级及以上(但不低于)和级发出以下警告。g++版本9.3.0和10.2展示了这一点 $g++-O3-Wall-Wextra-pedantic-std=c++17-Wstrict overflow=3 a.cpp a、 cpp:在函数“void std::push_heap(_RAIter,_RAIter)[with _RAIter=long unsigned

根据第3级的文件:

还警告[s]其他简化比较的情况。例如:x+1>1简化为x>0

如果将优化设置为
-O2
且高于但不低于,则如下所示的MWE在3级及以上(但不低于)和级发出以下警告。g++版本9.3.0和10.2展示了这一点

$g++-O3-Wall-Wextra-pedantic-std=c++17-Wstrict overflow=3 a.cpp
a、 cpp:在函数“void std::push_heap(_RAIter,_RAIter)[with _RAIter=long unsigned int*]”中: a、 cpp:8:1:警告:假设在将X+-C1 cmp C2更改为X cmp C2-+C1[-Wstrict overflow]时未发生有符号溢出

MWE

#include <algorithm>

int main() {
  std::size_t v[] = {0,10,3};
  std::make_heap(std::begin(v),std::end(v));
  std::pop_heap(std::begin(v),std::end(v));
  std::push_heap(std::begin(v),std::end(v)); // <---
}
#包括
int main(){
std::size_t v[]={0,10,3};
std::make_heap(std::begin(v),std::end(v));
std::pop_堆(std::begin(v),std::end(v));
std::push_堆(std::begin(v),std::end(v));//
  • 这是库实现中的错误吗?我没有看到任何签名类型
否。库实现正确。使用
-fsanitize=undefined
确认没有溢出

警告只告诉您编译器假设没有发生溢出。如果它假设代码没有未定义的行为,那么它可以更积极地优化代码,因此它假设代码没有溢出。警告只是告诉您这样的假设是成立的,因为如果您向实际导致溢出的函数

因此,警告意味着“您最好不要在此处提供错误的输入,因为这会使此优化产生错误的结果”

我报告了一个编译器bug(),但严格来说,GCC的行为与文档中的一样

  • 如何在保持-Wstrict溢出处于最大级别5的情况下修复此问题

-Wstrict overflow
的文档很明显会给出误报,所以不要将其与
-Werror
组合,这太傻了。

有符号类型在
std::\uu push\u heap
中,用于索引:
while(\uu holeIndex>\uu topinex&…)
。如果从
std::\uu push\u heap中删除此比较,警告将消失。库中没有错误。编译器会告诉您它假定没有整数溢出,而不是实际有溢出。使用
-fsanitize=undefined
编译时,显示运行时没有溢出。@JonathanWakely如果是暗示这是一个假设,这不是一个“信息”吗级别诊断?因为这是作为警告诊断发出的,这似乎不受欢迎。@这也是我的评估。标准库不应该抛出警告。任何警告。除非它们来自用户代码,我认为在这种情况下它们不会发出警告。文档很清楚:“因此,此警告很容易产生误报:关于代码的警告实际上不是问题。”将此警告与
-Werror
结合使用有点愚蠢。您得到了您想要的。