C++ 向量::在libc+中清除+;对于平凡的可破坏类型

C++ 向量::在libc+中清除+;对于平凡的可破坏类型,c++,c++11,clang,llvm,stdvector,C++,C++11,Clang,Llvm,Stdvector,如果T是可破坏的,那么vector::clear()会是O(1)吗 gcc在bits/stl_vector.h中的实现调用std::_Destroy(bits/stl_construct.h)。此实现通过在std::上分配标记来优化T可被平凡破坏的情况,它是可被平凡破坏的 查看llvm(3.5.0)的实现,vector::clear对每个元素调用std::allocator::destroy,然后调用析构函数 _LIBCPP_INLINE_VISIBILITY void destroy(poi

如果
T
是可破坏的,那么
vector::clear()
会是
O(1)

gcc在
bits/stl_vector.h
中的实现调用
std::_Destroy
bits/stl_construct.h
)。此实现通过在
std::上分配标记来优化T可被平凡破坏的情况,它是可被平凡破坏的

查看llvm(3.5.0)的实现,
vector::clear
对每个元素调用
std::allocator::destroy
,然后调用析构函数

 _LIBCPP_INLINE_VISIBILITY void destroy(pointer __p) {__p->~_Tp();}

在libc++中使用
vector::clear()
O(1)
,这会不会最终得到优化?

一般来说,对于具有非平凡析构函数的类型,一致性实现无法在O(1)中实现
std::vector::clear

C++11[container.requirements.general]/3说明:

对于受此子类影响并声明分配器类型的组件,存储在这些组件中的对象应使用
allocator\u特性来构造,表明它仅在使用默认分配器时尝试执行此优化:

  /**
   * 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)
          std::_Destroy(std::__addressof(*__first));
      }
    };

  template<>
    struct _Destroy_aux<true>
    {
      template<typename _ForwardIterator>
        static void
        __destroy(_ForwardIterator, _ForwardIterator) { }
    };

  /**
   * Destroy a range of objects.  If the value_type of the object has
   * a trivial destructor, the compiler should optimize all of this
   * away, otherwise the objects' destructors must be invoked.
   */
  template<typename _ForwardIterator>
    inline void
    _Destroy(_ForwardIterator __first, _ForwardIterator __last)
    {
      typedef typename iterator_traits<_ForwardIterator>::value_type
                       _Value_type;
      std::_Destroy_aux<__has_trivial_destructor(_Value_type)>::
        __destroy(__first, __last);
    }

  /**
   * Destroy a range of objects using the supplied allocator.  For
   * nondefault allocators we do not optimize away invocation of 
   * destroy() even if _Tp has a trivial destructor.
   */

  template<typename _ForwardIterator, typename _Allocator>
    void
    _Destroy(_ForwardIterator __first, _ForwardIterator __last,
         _Allocator& __alloc)
    {
      typedef __gnu_cxx::__alloc_traits<_Allocator> __traits;
      for (; __first != __last; ++__first)
        __traits::destroy(__alloc, std::__addressof(*__first));
    }

  template<typename _ForwardIterator, typename _Tp>
    inline void
    _Destroy(_ForwardIterator __first, _ForwardIterator __last,
         allocator<_Tp>&)
    {
      _Destroy(__first, __last);
    }
应输出:

constructed 1 constructed 2 constructed 3 destroying 3 destroying 2 destroying 1 构造1 构造2 构造3 摧毁3 摧毁2 摧毁1
(元素销毁的顺序未指定,因此“销毁”行可以是任意顺序,但必须全部存在。)libstdc++错误地“优化”了对
allocator::construct
allocator::destroy
的调用,但libc++当然正确地处理了它()。

0*N(销毁)之间的区别是什么N*0(销毁)?注意
destroy
是一个很容易的noop。然后我们在
vector::clear
上循环,添加到一个(本地)指针,与另一个(本地)指针进行比较以终止,并在每一步执行一个noop。编译器可能假设所有循环都终止,因此它可以在不证明循环条件成功的情况下修剪循环,并将循环指针分配给最终指针。此作业未使用。所以我可以看到一组优化步骤。@DieterLück你仍然有一个循环在上面。不过我理解你的意思——这似乎是一个微不足道的禁忌。然而,gcc最终得到了一个标记分派的助手。看到这个实现,我不确定我的结论,这是一个“微不足道的不可操作的东西”。@Yakk@DieterLücking也许我的问题真的应该是,为什么gcc会为
std::\u Destroy
的实现而烦恼。你为什么这么说?谢谢@Pradhan好吧,它在-O0版本中有效,而依赖优化的版本则不行。回答得好!谢谢。仅供参考,我报告了这一不符合项,尽管我认为这可能无关紧要。我将让libstdc++开发人员自己决定。 constructed 1 constructed 2 constructed 3 destroying 3 destroying 2 destroying 1