STL 源码剖析 -- Allocator 内存分配全揭秘
1、std::allocator
操作符 new 申请内存成功后,调用构造函数初始化内存。另外一种申请内存的方法是调用 operator new() 函数,该函数只申请内存,不执行构造函数。
#include <iostream> class Foo { public: Foo() { std::cout << "Foo::ctor" << std::endl; } ~Foo() { std::cout << "Foo::dtor" << std::endl; } }; int main() { { std::cout << "======" << std::endl; Foo* foo = new Foo; delete foo; } { std::cout << "======" << std::endl; Foo* foo = static_cast<Foo*>(::operator new(sizeof(Foo))); ::operator delete(foo); } return 0; }
上述程序输出为
====== Foo::ctor Foo::dtor ======
申请内存后如何构造对象呢,可以使用 placement new 函数,如下。
Foo* foo = static_cast<Foo*>(::operator new(sizeof(Foo))); new (foo) Foo(); foo->~Foo(); ::operator delete(foo);
1.1、std::allocator
std::allocator 旨在将内存申请与对象构造分离。std::allocator 直接继承 __new_allocator
template<typename _Tp> using __allocator_base = __new_allocator<_Tp>; template<typename _Tp> class allocator : public __allocator_base<_Tp> { public: typedef _Tp value_type; typedef size_t size_type; typedef ptrdiff_t difference_type; #if __cplusplus <= 201703L // These were removed for C++20. typedef _Tp* pointer; typedef const _Tp* const_pointer; typedef _Tp& reference; typedef const _Tp& const_reference; template<typename _Tp1> struct rebind { typedef allocator<_Tp1> other; }; #endif #if __cplusplus >= 201103L // _GLIBCXX_RESOLVE_LIB_DEFECTS // 2103. std::allocator propagate_on_container_move_assignment using propagate_on_container_move_assignment = true_type; using is_always_equal _GLIBCXX20_DEPRECATED_SUGGEST("std::allocator_traits::is_always_equal") = true_type; #endif /* ... */ };
allocator::rebind 是为了从一种类型,获取另外一种类型的 allocator,两种 allocator 是相同种类的分配器。
1.2、__new_allocator
__new_allocator 是一个空类,没有任何成员变量
template<typename _Tp> class __new_allocator { public: typedef _Tp value_type; typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; #if __cplusplus <= 201703L typedef _Tp* pointer; typedef const _Tp* const_pointer; typedef _Tp& reference; typedef const _Tp& const_reference; template<typename _Tp1> struct rebind { typedef __new_allocator<_Tp1> other; }; #endif #if __cplusplus >= 201103L // _GLIBCXX_RESOLVE_LIB_DEFECTS // 2103. propagate_on_container_move_assignment typedef std::true_type propagate_on_container_move_assignment; #endif
allocate/deallocate 分配调用 operator new() 和 operator delete() 申请和释放内存。
_GLIBCXX_NODISCARD _Tp* allocate(size_type __n, const void* = static_cast<const void*>(0)) { #if __cplusplus >= 201103L // _GLIBCXX_RESOLVE_LIB_DEFECTS // 3308. std::allocator<void>().allocate(n) static_assert(sizeof(_Tp) != 0, "cannot allocate incomplete types"); #endif if (__builtin_expect(__n > this->_M_max_size(), false)) { // _GLIBCXX_RESOLVE_LIB_DEFECTS // 3190. allocator::allocate sometimes returns too little storage if (__n > (std::size_t(-1) / sizeof(_Tp))) std::__throw_bad_array_new_length(); std::__throw_bad_alloc(); } #if __cpp_aligned_new if (alignof(_Tp) > __STDCPP_DEFAULT_NEW_ALIGNMENT__) { std::align_val_t __al = std::align_val_t(alignof(_Tp)); return static_cast<_Tp*>(_GLIBCXX_OPERATOR_NEW(__n * sizeof(_Tp), __al)); } #endif return static_cast<_Tp*>(_GLIBCXX_OPERATOR_NEW(__n * sizeof(_Tp))); } // __p is not permitted to be a null pointer. void deallocate(_Tp* __p, size_type __n __attribute__ ((__unused__))) { #if __cpp_sized_deallocation # define _GLIBCXX_SIZED_DEALLOC(p, n) (p), (n) * sizeof(_Tp) #else #endif #if __cpp_aligned_new if (alignof(_Tp) > __STDCPP_DEFAULT_NEW_ALIGNMENT__) { _GLIBCXX_OPERATOR_DELETE(_GLIBCXX_SIZED_DEALLOC(__p, __n), std::align_val_t(alignof(_Tp))); return; } #endif _GLIBCXX_OPERATOR_DELETE(_GLIBCXX_SIZED_DEALLOC(__p, __n)); }
construct()/destroy() 赋值对象的构造和析构。
template<typename _Up, typename... _Args> void construct(_Up* __p, _Args&&... __args) noexcept(std::is_nothrow_constructible<_Up, _Args...>::value) { ::new((void *)__p) _Up(std::forward<_Args>(__args)...); } template<typename _Up> void destroy(_Up* __p) noexcept(std::is_nothrow_destructible<_Up>::value) { __p->~_Up(); }
2、allocator_traits
用户不仅可以使用 std::allocator,还可以使用自定义的 allocator。allocator_traits 提供了一种标准的接口取访问 allocator 的成员变量、成员函数,以及定义的类型。
struct __allocator_traits_base { template<typename _Tp, typename _Up, typename = void> struct __rebind : __replace_first_arg<_Tp, _Up> { }; template<typename _Tp, typename _Up> struct __rebind<_Tp, _Up, __void_t<typename _Tp::template rebind<_Up>::other>> { using type = typename _Tp::template rebind<_Up>::other; }; protected: template<typename _Tp> using __pointer = typename _Tp::pointer; template<typename _Tp> using __c_pointer = typename _Tp::const_pointer; template<typename _Tp> using __v_pointer = typename _Tp::void_pointer; template<typename _Tp> using __cv_pointer = typename _Tp::const_void_pointer; template<typename _Tp> using __pocca = typename _Tp::propagate_on_container_copy_assignment; template<typename _Tp> using __pocma = typename _Tp::propagate_on_container_move_assignment; template<typename _Tp> using __pocs = typename _Tp::propagate_on_container_swap; template<typename _Tp> using __equal = typename _Tp::is_always_equal; }; template<typename _Alloc, typename _Up> using __alloc_rebind = typename __allocator_traits_base::template __rebind<_Alloc, _Up>::type; /// @endcond /** * @brief Uniform interface to all allocator types. * @headerfile memory * @ingroup allocators * @since C++11 */ template<typename _Alloc> struct allocator_traits : __allocator_traits_base { /// The allocator type typedef _Alloc allocator_type; /* ... */ };
allocate() 和 deallocate() 调用底层 allocator 对应的函数。
_GLIBCXX_NODISCARD static _GLIBCXX20_CONSTEXPR pointer allocate(_Alloc& __a, size_type __n) { return __a.allocate(__n); } static _GLIBCXX20_CONSTEXPR void deallocate(_Alloc& __a, pointer __p, size_type __n) { __a.deallocate(__p, __n); }
construct() 需要判断底层 allocator 是否定义了 construct 函数(能够处理传入的参数),如果可以,就调用,否则使用 placement new() 调用构造函数
template<typename _Tp, typename... _Args> static _GLIBCXX20_CONSTEXPR auto construct(_Alloc& __a, _Tp* __p, _Args&&... __args) noexcept(noexcept(_S_construct(__a, __p, std::forward<_Args>(__args)...))) -> decltype(_S_construct(__a, __p, std::forward<_Args>(__args)...)) { _S_construct(__a, __p, std::forward<_Args>(__args)...); }
_S_construct() 的第二个定义就是使用 placement new() 构造对象。
template<typename _Tp, typename... _Args> static _GLIBCXX14_CONSTEXPR _Require<__has_construct<_Tp, _Args...>> _S_construct(_Alloc& __a, _Tp* __p, _Args&&... __args) noexcept(noexcept(__a.construct(__p, std::forward<_Args>(__args)...))) { __a.construct(__p, std::forward<_Args>(__args)...); } template<typename _Tp, typename... _Args> static _GLIBCXX14_CONSTEXPR _Require<__and_<__not_<__has_construct<_Tp, _Args...>>, is_constructible<_Tp, _Args...>>> _S_construct(_Alloc&, _Tp* __p, _Args&&... __args) noexcept(std::is_nothrow_constructible<_Tp, _Args...>::value) { #if __cplusplus <= 201703L ::new((void*)__p) _Tp(std::forward<_Args>(__args)...); #else std::construct_at(__p, std::forward<_Args>(__args)...); #endif }
destroy() 也是如此
template<typename _Tp> static _GLIBCXX20_CONSTEXPR void destroy(_Alloc& __a, _Tp* __p) noexcept(noexcept(_S_destroy(__a, __p, 0))) { _S_destroy(__a, __p, 0); } template<typename _Alloc2, typename _Tp> static _GLIBCXX14_CONSTEXPR auto _S_destroy(_Alloc2& __a, _Tp* __p, int) noexcept(noexcept(__a.destroy(__p))) -> decltype(__a.destroy(__p)) { __a.destroy(__p); } template<typename _Alloc2, typename _Tp> static _GLIBCXX14_CONSTEXPR void _S_destroy(_Alloc2&, _Tp* __p, ...) noexcept(std::is_nothrow_destructible<_Tp>::value) { std::_Destroy(__p); }
如果是 std::allocator,construct() 和 destroy() 直接调用 std::allocator 的函数构造和释放对象。
template<typename _Tp> struct allocator_traits<allocator<_Tp>> { /* ... */ template<typename _Up, typename... _Args> static _GLIBCXX20_CONSTEXPR void construct(allocator_type& __a __attribute__((__unused__)), _Up* __p, _Args&&... __args) noexcept(std::is_nothrow_constructible<_Up, _Args...>::value) { #if __cplusplus <= 201703L __a.construct(__p, std::forward<_Args>(__args)...); #else std::construct_at(__p, std::forward<_Args>(__args)...); #endif } template<typename _Up> static _GLIBCXX20_CONSTEXPR void destroy(allocator_type& __a __attribute__((__unused__)), _Up* __p) noexcept(is_nothrow_destructible<_Up>::value) { #if __cplusplus <= 201703L __a.destroy(__p); #else std::destroy_at(__p); #endif } };
__gnu_cxx::__alloc_traits 是对 std::allocator_traits 的封装
template<typename _Alloc, typename = typename _Alloc::value_type> struct __alloc_traits #if __cplusplus >= 201103L : std::allocator_traits<_Alloc> #endif { typedef _Alloc allocator_type; #if __cplusplus >= 201103L typedef std::allocator_traits<_Alloc> _Base_type; typedef typename _Base_type::value_type value_type; typedef typename _Base_type::pointer pointer; typedef typename _Base_type::const_pointer const_pointer; typedef typename _Base_type::size_type size_type; typedef typename _Base_type::difference_type difference_type; // C++11 allocators do not define reference or const_reference typedef value_type& reference; typedef const value_type& const_reference; using _Base_type::allocate; using _Base_type::deallocate; using _Base_type::construct; using _Base_type::destroy; using _Base_type::max_size; private: template<typename _Ptr> using __is_custom_pointer = std::__and_<std::is_same<pointer, _Ptr>, std::__not_<std::is_pointer<_Ptr>>>; public: // overload construct for non-standard pointer types template<typename _Ptr, typename... _Args> static _GLIBCXX14_CONSTEXPR std::__enable_if_t<__is_custom_pointer<_Ptr>::value> construct(_Alloc& __a, _Ptr __p, _Args&&... __args) noexcept(noexcept(_Base_type::construct(__a, std::__to_address(__p), std::forward<_Args>(__args)...))) { _Base_type::construct(__a, std::__to_address(__p), std::forward<_Args>(__args)...); } // overload destroy for non-standard pointer types template<typename _Ptr> static _GLIBCXX14_CONSTEXPR std::__enable_if_t<__is_custom_pointer<_Ptr>::value> destroy(_Alloc& __a, _Ptr __p) noexcept(noexcept(_Base_type::destroy(__a, std::__to_address(__p)))) { _Base_type::destroy(__a, std::__to_address(__p)); } static constexpr _Alloc _S_select_on_copy(const _Alloc& __a) { return _Base_type::select_on_container_copy_construction(__a); } static _GLIBCXX14_CONSTEXPR void _S_on_swap(_Alloc& __a, _Alloc& __b) { std::__alloc_on_swap(__a, __b); } static constexpr bool _S_propagate_on_copy_assign() { return _Base_type::propagate_on_container_copy_assignment::value; } static constexpr bool _S_propagate_on_move_assign() { return _Base_type::propagate_on_container_move_assignment::value; } static constexpr bool _S_propagate_on_swap() { return _Base_type::propagate_on_container_swap::value; } static constexpr bool _S_always_equal() { return _Base_type::is_always_equal::value; } static constexpr bool _S_nothrow_move() { return _S_propagate_on_move_assign() || _S_always_equal(); } template<typename _Tp> struct rebind { typedef typename _Base_type::template rebind_alloc<_Tp> other; }; #else // ! C++11 #endif // C++11 };
3、std::_Construct()/std::_Destroy()
这两个是内部函数,分别用于构成和析构对象。
3.1、std::_Construct()
_Construct() 的实现比较简单,调用 placement new() 使用构造函数构造对象。
#if __cplusplus >= 201103L template<typename _Tp, typename... _Args> _GLIBCXX20_CONSTEXPR inline void _Construct(_Tp* __p, _Args&&... __args) { #if __cplusplus >= 202002L /* ... */ #endif ::new((void*)__p) _Tp(std::forward<_Args>(__args)...); } #else /* ... */ #endif
3.2、std::_Destroy()
析构单个对象,直接调用对象的析构函数。
template<typename _Tp> _GLIBCXX14_CONSTEXPR inline void _Destroy(_Tp* __pointer) { #if __cplusplus > 201703L std::destroy_at(__pointer); #else __pointer->~_Tp(); #endif }
如果析构 [first, last) 迭代器范围内的对象,需要借助 _Destroy_aux 对象。
template<typename _ForwardIterator> _GLIBCXX20_CONSTEXPR inline void _Destroy(_ForwardIterator __first, _ForwardIterator __last) { typedef typename iterator_traits<_ForwardIterator>::value_type _Value_type; #if __cplusplus >= 201103L // A deleted destructor is trivial, this ensures we reject such types: static_assert(is_destructible<_Value_type>::value, "value type is destructible"); #endif #if __cplusplus >= 202002L /* ... */ #endif std::_Destroy_aux<__has_trivial_destructor(_Value_type)>:: __destroy(__first, __last); }
_Destroy_aux 如果模板参数为 true,其成员函数 __destroy() 为空,什么都不做。
template<bool> struct _Destroy_aux { template<typename _ForwardIterator> static _GLIBCXX20_CONSTEXPR 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 的定义,如果对象的析构函数是 trivial 的(比如默认析构析构函数),则 _Destroy() 不会调用其析构函数,直接返回。
4、std::copy()
std::copy() 会尽量使用 memmove() 函数来完成对象的拷贝。
template<typename _II, typename _OI> _GLIBCXX20_CONSTEXPR inline _OI copy(_II __first, _II __last, _OI __result) { // concept requirements __glibcxx_function_requires(_InputIteratorConcept<_II>) __glibcxx_function_requires(_OutputIteratorConcept<_OI, typename iterator_traits<_II>::reference>) __glibcxx_requires_can_increment_range(__first, __last, __result); return std::__copy_move_a<__is_move_iterator<_II>::__value> (std::__miter_base(__first), std::__miter_base(__last), __result); }
__copy_move_a ==> __copy_move_a1 ==> __copy_move_a2
这里没有考虑 deque 和 istreambuf_iterator。 __copy_move_a1 对于 deque 有不同的实现, __copy_move_a2 也针对 istreambuf_iterator 做了区分,这里不深究。
template<bool _IsMove, typename _II, typename _OI> _GLIBCXX20_CONSTEXPR inline _OI __copy_move_a(_II __first, _II __last, _OI __result) { return std::__niter_wrap(__result, std::__copy_move_a1<_IsMove>(std::__niter_base(__first), std::__niter_base(__last), std::__niter_base(__result))); } template<bool _IsMove, typename _II, typename _OI> _GLIBCXX20_CONSTEXPR inline _OI __copy_move_a1(_II __first, _II __last, _OI __result) { return std::__copy_move_a2<_IsMove>(__first, __last, __result); } template<bool _IsMove, typename _II, typename _OI> _GLIBCXX20_CONSTEXPR inline _OI __copy_move_a2(_II __first, _II __last, _OI __result) { typedef typename iterator_traits<_II>::iterator_category _Category; #ifdef __cpp_lib_is_constant_evaluated /* ... */ #endif return std::__copy_move<_IsMove, __memcpyable<_OI, _II>::__value, _Category>::__copy_m(__first, __last, __result); }
抽丝剥茧,最后调用 __copy_move::__copy_m() 成员函数完成对象拷贝。
__copy_move 三个模板函数
- _IsMove表示是否支持 move
- _IsSimple 表示对象是否可以直接拷贝内存,不用执行构造函数
- _Category 表示迭代器类型
__copy_move 只有两个目的
- 尽量使用 memmove
- 如果是 random access iterator,循环使用确切的 count
template<bool _IsMove, bool _IsSimple, typename _Category> struct __copy_move { template<typename _II, typename _OI> _GLIBCXX20_CONSTEXPR static _OI __copy_m(_II __first, _II __last, _OI __result) { for (; __first != __last; ++__result, (void)++__first) *__result = *__first; return __result; } };
4.1、IsMove(true) + IsSimple(false)
使用移动赋值函数
template<typename _Category> struct __copy_move<true, false, _Category> { template<typename _II, typename _OI> _GLIBCXX20_CONSTEXPR static _OI __copy_m(_II __first, _II __last, _OI __result) { for (; __first != __last; ++__result, (void)++__first) *__result = std::move(*__first); return __result; } };
4.2、IsMove(false) + IsSimple(false) + random
使用普通赋值函数,loop 使用 count 计数
template<> struct __copy_move<false, false, random_access_iterator_tag> { template<typename _II, typename _OI> _GLIBCXX20_CONSTEXPR static _OI __copy_m(_II __first, _II __last, _OI __result) { typedef typename iterator_traits<_II>::difference_type _Distance; for(_Distance __n = __last - __first; __n > 0; --__n) { *__result = *__first; ++__first; ++__result; } return __result; }
4.3、IsMove(true) + IsSimple(false) + random
使用移动赋值函数,loop 使用 count 计数
template<> struct __copy_move<true, false, random_access_iterator_tag> { template<typename _II, typename _OI> _GLIBCXX20_CONSTEXPR static _OI __copy_m(_II __first, _II __last, _OI __result) { typedef typename iterator_traits<_II>::difference_type _Distance; for(_Distance __n = __last - __first; __n > 0; --__n) { *__result = std::move(*__first); ++__first; ++__result; } return __result; } };
4.4、IsSimple(true) + random
使用 memmove 拷贝对象
template<bool _IsMove> struct __copy_move<_IsMove, true, random_access_iterator_tag> { template<typename _Tp> _GLIBCXX20_CONSTEXPR static _Tp* __copy_m(const _Tp* __first, const _Tp* __last, _Tp* __result) { #if __cplusplus >= 201103L using __assignable = __conditional_t<_IsMove, is_move_assignable<_Tp>, is_copy_assignable<_Tp>>; // trivial types can have deleted assignment static_assert( __assignable::value, "type must be assignable" ); #endif const ptrdiff_t _Num = __last - __first; if (_Num) __builtin_memmove(__result, __first, sizeof(_Tp) * _Num); return __result + _Num; } };
5、std::fill()
std::fill() 具有和 std::copy() 相似的逻辑:尽量调用 memset() 完成赋值。
template<typename _ForwardIterator, typename _Tp> _GLIBCXX20_CONSTEXPR inline void fill(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) { // concept requirements __glibcxx_function_requires(_Mutable_ForwardIteratorConcept< _ForwardIterator>) __glibcxx_requires_valid_range(__first, __last); std::__fill_a(__first, __last, __value); } template<typename _FIte, typename _Tp> _GLIBCXX20_CONSTEXPR inline void __fill_a(_FIte __first, _FIte __last, const _Tp& __value) { std::__fill_a1(__first, __last, __value); }
__fill_a1() 对于 scalar 和 byte 类型做了优化
- scalar 类型添加 const 做编译优化
- byte 类型使用 memset
template<typename _ForwardIterator, typename _Tp> _GLIBCXX20_CONSTEXPR inline typename __gnu_cxx::__enable_if<!__is_scalar<_Tp>::__value, void>::__type __fill_a1(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) { for (; __first != __last; ++__first) *__first = __value; } template<typename _ForwardIterator, typename _Tp> _GLIBCXX20_CONSTEXPR inline typename __gnu_cxx::__enable_if<__is_scalar<_Tp>::__value, void>::__type __fill_a1(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) { const _Tp __tmp = __value; for (; __first != __last; ++__first) *__first = __tmp; } // Specialization: for char types we can use memset. template<typename _Tp> _GLIBCXX20_CONSTEXPR inline typename __gnu_cxx::__enable_if<__is_byte<_Tp>::__value, void>::__type __fill_a1(_Tp* __first, _Tp* __last, const _Tp& __c) { const _Tp __tmp = __c; #if __cpp_lib_is_constant_evaluated /* ... */ #endif if (const size_t __len = __last - __first) __builtin_memset(__first, static_cast<unsigned char>(__tmp), __len); }
6、uninitialized* 算法
6.1、uninitialized_copy/uninitialized_copy_n
uninitialized_copy() 函数使用 __uninitialized_copy::__uninit_copy() 成员函数拷贝对象。
template<typename _InputIterator, typename _ForwardIterator> inline _ForwardIterator uninitialized_copy(_InputIterator __first, _InputIterator __last, _ForwardIterator __result) { typedef typename iterator_traits<_InputIterator>::value_type _ValueType1; typedef typename iterator_traits<_ForwardIterator>::value_type _ValueType2; // _ValueType1 must be trivially-copyable to use memmove, so don't // bother optimizing to std::copy if it isn't. // XXX Unnecessary because std::copy would check it anyway? const bool __can_memmove = __is_trivial(_ValueType1); #if __cplusplus < 201103L /* ... */ #else using _From = decltype(*__first); #endif const bool __assignable = _GLIBCXX_USE_ASSIGN_FOR_INIT(_ValueType2, _From); return std::__uninitialized_copy<__can_memmove && __assignable>:: __uninit_copy(__first, __last, __result); }
__uninitialized_copy 针对对象类型做了优化:
- trivial 类使用 __do_uninit_copy(),调用 std::_Construct 在内存上构造对象。构造函数抛出异常,已经构造的对象会被析构。
- 否则使用 std::copy() 拷贝对象
template<bool _TrivialValueTypes> struct __uninitialized_copy { template<typename _InputIterator, typename _ForwardIterator> static _ForwardIterator __uninit_copy(_InputIterator __first, _InputIterator __last, _ForwardIterator __result) { return std::__do_uninit_copy(__first, __last, __result); } }; template<> struct __uninitialized_copy<true> { template<typename _InputIterator, typename _ForwardIterator> static _ForwardIterator __uninit_copy(_InputIterator __first, _InputIterator __last, _ForwardIterator __result) { return std::copy(__first, __last, __result); } }; template<typename _InputIterator, typename _ForwardIterator> _GLIBCXX20_CONSTEXPR _ForwardIterator __do_uninit_copy(_InputIterator __first, _InputIterator __last, _ForwardIterator __result) { _ForwardIterator __cur = __result; __try { for (; __first != __last; ++__first, (void)++__cur) std::_Construct(std::__addressof(*__cur), *__first); return __cur; } __catch(...) { std::_Destroy(__result, __cur); __throw_exception_again; } }
uninitialized_copy_n() 直接调用 __uninitialized_copy_n() 函数
template<typename _InputIterator, typename _Size, typename _ForwardIterator> inline _ForwardIterator uninitialized_copy_n(_InputIterator __first, _Size __n, _ForwardIterator __result) { return std::__uninitialized_copy_n(__first, __n, __result, std::__iterator_category(__first)); }
__uninitialized_copy_n() 函数区分迭代器类型做优化,如果不是 random_access_iterator_tag,就依次调用 [first, first + n) 迭代器构造。否则借助 uninitialized_copy() 拷贝。
template<typename _InputIterator, typename _Size, typename _ForwardIterator> _ForwardIterator __uninitialized_copy_n(_InputIterator __first, _Size __n, _ForwardIterator __result, input_iterator_tag) { _ForwardIterator __cur = __result; __try { for (; __n > 0; --__n, (void) ++__first, ++__cur) std::_Construct(std::__addressof(*__cur), *__first); return __cur; } __catch(...) { std::_Destroy(__result, __cur); __throw_exception_again; } } template<typename _RandomAccessIterator, typename _Size, typename _ForwardIterator> inline _ForwardIterator __uninitialized_copy_n(_RandomAccessIterator __first, _Size __n, _ForwardIterator __result, random_access_iterator_tag) { return std::uninitialized_copy(__first, __first + __n, __result); }
6.2、uninitialized_fill/uninitialized_fill_n
uninitialized_fill() 直接调用 __uninitialized_fill::__uninit_fill() 成员函数赋值
template<typename _ForwardIterator, typename _Tp> inline void uninitialized_fill(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __x) { typedef typename iterator_traits<_ForwardIterator>::value_type _ValueType; // Trivial types do not need a constructor to begin their lifetime, // so try to use std::fill to benefit from its memset optimization. const bool __can_fill = _GLIBCXX_USE_ASSIGN_FOR_INIT(_ValueType, const _Tp&); std::__uninitialized_fill<__can_fill>:: __uninit_fill(__first, __last, __x); }
如果是 trivial 类型,__uninitialized_fill 使用 std::fill() 完成赋值,否则调用构造函数。
template<typename _ForwardIterator, typename _Tp> _GLIBCXX20_CONSTEXPR void __do_uninit_fill(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __x) { _ForwardIterator __cur = __first; __try { for (; __cur != __last; ++__cur) std::_Construct(std::__addressof(*__cur), __x); } __catch(...) { std::_Destroy(__first, __cur); __throw_exception_again; } } template<bool _TrivialValueType> struct __uninitialized_fill { template<typename _ForwardIterator, typename _Tp> static void __uninit_fill(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __x) { std::__do_uninit_fill(__first, __last, __x); } }; template<> struct __uninitialized_fill<true> { template<typename _ForwardIterator, typename _Tp> static void __uninit_fill(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __x) { std::fill(__first, __last, __x); } };
uninitialized_fill_n() 也是相同的逻辑
template<typename _ForwardIterator, typename _Size, typename _Tp> inline _ForwardIterator uninitialized_fill_n(_ForwardIterator __first, _Size __n, const _Tp& __x) { typedef typename iterator_traits<_ForwardIterator>::value_type _ValueType; // Trivial types do not need a constructor to begin their lifetime, // so try to use std::fill_n to benefit from its optimizations. const bool __can_fill = _GLIBCXX_USE_ASSIGN_FOR_INIT(_ValueType, const _Tp&) // For arbitrary class types and floating point types we can't assume // that __n > 0 and std::__size_to_integer(__n) > 0 are equivalent, // so only use std::fill_n when _Size is already an integral type. && __is_integer<_Size>::__value; return __uninitialized_fill_n<__can_fill>:: __uninit_fill_n(__first, __n, __x); }
__uninitialized_fill_n 如果是 trivial 类型,调用 std::fill_n() 完成赋值,否则使用构造函数构造对象
template<typename _ForwardIterator, typename _Size, typename _Tp> _GLIBCXX20_CONSTEXPR _ForwardIterator __do_uninit_fill_n(_ForwardIterator __first, _Size __n, const _Tp& __x) { _ForwardIterator __cur = __first; __try { for (; __n > 0; --__n, (void) ++__cur) std::_Construct(std::__addressof(*__cur), __x); return __cur; } __catch(...) { std::_Destroy(__first, __cur); __throw_exception_again; } } template<bool _TrivialValueType> struct __uninitialized_fill_n { template<typename _ForwardIterator, typename _Size, typename _Tp> static _ForwardIterator __uninit_fill_n(_ForwardIterator __first, _Size __n, const _Tp& __x) { return std::__do_uninit_fill_n(__first, __n, __x); } }; template<> struct __uninitialized_fill_n<true> { template<typename _ForwardIterator, typename _Size, typename _Tp> static _ForwardIterator __uninit_fill_n(_ForwardIterator __first, _Size __n, const _Tp& __x) { return std::fill_n(__first, __n, __x); } };
欢迎关注公众号“源知源为”,阅读更多技术干货
#八股文##c++##STL#C/C++ 语言基础