C++ STL优化警告:代码问题还是更险恶的?

Zor*_*war 9 c++ optimization gcc stl vector

我有一个程序,我正在从使用数组切换到向量,但我遇到了问题.我把它减少到了这个:

#include <vector>

class A {
public:
A(void);
~A(void);

private:
std::vector< std::vector<int> > a;
};

A::A(void) : a() {}

A::~A(void) {}
Run Code Online (Sandbox Code Playgroud)

这给出了来自g ++(flags:-O2 -Wunsafe-loop-optimizations,版本4.4.3(Ubuntu 4.4.3-4ubuntu5)在Ubuntu 10.04 x86_64上)的以下警告:

/usr/include/c++/4.4/bits/stl_construct.h:在析构函数'A :: ~A()'中:/usr/include/c++/4.4/bits/stl_construct.h:92:警告:无法优化循环,循环计数器可能会溢出

那么,Leo给出了什么?矢量类不应该跟踪它有多少元素?那么,如果这是被引用的"计数器",它怎么会溢出?(编辑:这个问题或多或少已在下面得到解答,但是,对我来说,只留下必然结果:为什么还要警告库中的循环无法优化?为什么我,最终用户,应该关注那个问题? ?)

编辑:

这是关于被抱怨的相关代码(但是,正如我在评论中所说,我不明白为什么这应该是我的考虑因为我不应该担心库的实现):

/**
 * Destroy the object pointed to by a pointer type.
 */
template<typename _Tp>
  inline void
  _Destroy(_Tp* __pointer)
  { __pointer->~_Tp(); }

template<bool>
  struct _Destroy_aux
  {
    template<typename _ForwardIterator>
      static void
      __destroy(_ForwardIterator __first, _ForwardIterator __last)
    {
      for (; __first != __last; ++__first) // <-- this is line 92
        std::_Destroy(&*__first);
    }
  };
Run Code Online (Sandbox Code Playgroud)

更新:

好吧,我期待两个答案中的一个:我在我的代码中做了一些巧妙的异常(但不一定错误),或者消息非常字面地告诉我,库中指向的循环无法优化.感激地保证它不是前者,是否会报告来自gcc的自己的库预期行为的警告,还是应该报告?(似乎不值得提出另一个问题来问这个新问题的借口.)

更新2:

好的,感谢所有信息人员:这是编译器中的一个错误.仅供参考,我从GNU(版本4.5.2)编译了一个不受干扰的编译器和c ++库,它没有显示这种行为(库代码是相同的),所以我猜这样的警告不应该出现.再次感谢大家.

小智 6

它只是意味着编译器无法证明它不会溢出.由于你有-O2,你要求对循环进行某些优化.只有在可以证明这些条件的情况下,才能完成其中一些优化.您要求的编译器警告告诉您某些循环无法优化(我猜它可能是矢量底层数组的内联破坏循环.

我想你可以忽略这个警告.但是我不得不想知道为什么你首先在编译选项中要求这个警告?

  • 我只是要迂腐:我会忽略这个警告,因为我的理解是这样,那么如果不能优化呢?但是,对于像这样的基本情况,gcc不应该只是放松一下吗? (2认同)
  • @Zorawar:你看过GCC给你的警告了吗?它不是"抱怨自己的图书馆".它告诉你"我无法做你所问的".您要求它优化循环,然后您要求它警告您是否找到任何无法优化的循环.然后它找到了一个无法优化的循环,并且,就像你要求的那样,它会警告你它发现了一个无法优化的循环. (2认同)

Mat*_* M. 2

我想我终于明白了编译器的暗示。

循环不是在整数上执行的,所以我认为编译器试图告诉的是它实际上无法计算循环将执行多少次运行。

您使用的警告实际上应该与-funsafe-loop-optimizations来自gcc 优化选项页面的警告结合在一起:

-funsafe-loop-optimizations 如果给定,循环优化器将假设循环索引不会溢出,并且具有重要退出条件的循环不是无限的。即使循环优化器本身无法证明这些假设是有效的,这也可以实现更广泛的循环优化。使用 -Wunsafe-loop-optimizations`,如果编译器发现这种循环,它会警告您。

我必须承认,我认为编译器总是被允许假设循环最终会终止,因为推断它需要解决一般情况下无法解决的停止问题。

但在这里,如果你看一下这个函数,就不可能证明循环不会溢出,原因很简单:firstto 的范围last可能格式不正确。

  • 可能是这样first > last(注意:不能比较前向迭代器)
  • 可能是对齐*关闭,指针上 ( T*)++相当于+= sizeof(T),并且因为!=使用 a 代替<,所以如果是这种情况,first可能会跳过last

当然,这在实践中永远不会发生,因为库编写者已确保他们向方法传递了正确的参数,但编译器无法推断它,因此会出现警告。

尽管如此,我还是感到惊讶,我本以为编译器编写者会故意忽略他们自己的库提出的警告,因为他们必须使用那些轻微的手,这样我们就不会这样做。

(*) 这里不是内存对齐,我只是暗示这样一个事实,错误的校准T*实际上可能指向 a 内T,并且sizeof(T)一次前进实际上永远不会让它回到边界上T......