STL glibc list的size方法
所以仅仅是判断list容器是否有元素存在应该使用empty而不是list,避免进入复杂度为O(N)的重载函数中导致入坑
bool empty() const { return _M_node->_M_next == _M_node; }
size_type size() const {
size_type __result = 0;
distance(begin(), end(), __result);
return __result;
}
template<class InputIterator>
inline typename iterator_traits<InputIterator>::difference_type
distance(InputIterator first, InputIterator last) {
typedef typename
iterator_traits<Iterator>::iterator_category category;
return __distance(first, last, category());
}
//__distance函数根据迭代器类型的不同版本,效率也不尽相同
template<class InputIterator>
inline typename iterator_traits<InputIterator>::difference_type
__distance(InputIterator first, InputIterator last,
input_iterator_tag) {
iterator_traits<InputIterator>::difference_type n = 0;
//遍历 复杂度O(N)
while (first != last) {
++first; ++n;
}
return n;
}
template<class RandomAccessIterator>
inline typename iterator_traits<RandomAccessIterator>::difference_type
__distance(RandomAccessIterator first, RandomAccessIterator last,
random_access_iterator_tag) {
//头尾差值 复杂度O(1)
return last - first;
void splice(iterator __position, list& __x) {
if (!__x.empty())
this->transfer(__position, __x.begin(), __x.end());
}
void splice(iterator __position, list&, iterator __i) {
iterator __j = __i;
++__j;
if (__position == __i || __position == __j) return;
this->transfer(__position, __i, __j);
}
void splice(iterator __position, list&, iterator __first, iterator __last) {
if (__first != __last)
this->transfer(__position, __first, __last);
}
}
void transfer(iterator __position, iterator __first, iterator __last) {
if (__position != __last) {
// Remove [first, last) from its old position.
__last._M_node->_M_prev->_M_next = __position._M_node;
__first._M_node->_M_prev->_M_next = __last._M_node;
__position._M_node->_M_prev->_M_next = __first._M_node;
// Splice [first, last) into its new position.
_List_node_base* __tmp = __position._M_node->_M_prev;
__position._M_node->_M_prev = __last._M_node->_M_prev;
__last._M_node->_M_prev = __first._M_node->_M_prev;
__first._M_node->_M_prev = __tmp;
}
}
配合下面这张图更好理解transfer操作
如果使用成员变量维护的话,需要去遍历迭代器拼接区间元素数量从而使得transfer复杂度变高了。如果size()使用遍历的方法去获取元素数量,那么transfer操作则不需要关心list元素个数变化。以此牺牲了size()方法的效率
不过C++11已经是对于size()方法维护了一个成员变量
图片来源<<stl源码剖析>>,代码来源github stl源码