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