前言

    在SGI STL中,list容器是一个循环的双向链表,它的内存空间效率较前文介绍的vector容器高。因为vector容器的内存空间是连续存储的,且在分配内存空间时,会分配额外的可用空间;而list容器的内存空间不一定是连续存储,内存之间是采用迭代器或节点指针进行连接,并且在插入或删除数据节点时,就配置或释放一个数据节点,并不会分配额外的内存空间,这两个操作过程都是常数时间。

    与vector容器不同的是list容器在进行插入操作或拼接操作时,迭代器并不会失效;且不能以普通指针作为迭代器,因为普通指针的+或-操作只能指向连续空间的后移地址或前移个地址,不能保证指向list的下一个节点,迭代器必须是双向迭代器,因为list容器具备有前移和后移的能力。

    注:本文所列的源码出自SGI STL中的文件<stl_list.h>,对于list容器类的详细信息也可以查看list容器库》MSDNlist类》

list容器

list节点和list数据结构

    在list容器中,list本身和list节点是分开设计的,list节点结构是存储数据和指向相邻节点的指针;如下源码所示:

//以下是list链表节点的数据结构
struct _List_node_base {_List_node_base* _M_next;//指向直接后继节点_List_node_base* _M_prev;//指向直接前驱节点
};template <class _Tp>
struct _List_node : public _List_node_base {_Tp _M_data;//节点存储的数据
};
       list本身的数据结构是只有一个指向链表节点的指针,因为list容器是循环双向链表,则足够遍历整个链表;如下源码所示:

//以下是双向链表list类的定义,分配器_Alloc默认为第二级配置器
template <class _Tp, class _Alloc = __STL_DEFAULT_ALLOCATOR(_Tp) >
class list : protected _List_base<_Tp, _Alloc> { ...
public:typedef _List_node<_Tp> _Node;
protected://定义指向链表节点指针_List_node<_Tp>* _M_node;...
};
    下面给出list节点和list本身的数据结构图:


list容器的迭代器

       list容器的内存空间存储不一定是连续的,则不能用普通指针做为迭代器;list容器的迭代器是双向迭代器,这也是导致list容器的排序成员函数sort()不能使用STL算法中的排序函数,因为STL中的排序算法接受的迭代器是随机访问迭代器;list容器在进行插入和拼接操作时迭代器不会失效;以下是源码对迭代器的定义:

//以下是链表List_iterator_base的迭代器
struct _List_iterator_base {//数据类型typedef size_t                     size_type;typedef ptrdiff_t                  difference_type;//list迭代器的类型是双向迭代器bidirectional_iteratortypedef bidirectional_iterator_tag iterator_category;//定义指向链表节点的指针_List_node_base* _M_node;//构造函数_List_iterator_base(_List_node_base* __x) : _M_node(__x) {}_List_iterator_base() {}//更新节点指针,指向直接前驱或直接后继节点void _M_incr() { _M_node = _M_node->_M_next; }void _M_decr() { _M_node = _M_node->_M_prev; }//操作符重载bool operator==(const _List_iterator_base& __x) const {return _M_node == __x._M_node;}bool operator!=(const _List_iterator_base& __x) const {return _M_node != __x._M_node;}
};  //以下是链表List_iterator的迭代器
template<class _Tp, class _Ref, class _Ptr>
struct _List_iterator : public _List_iterator_base {typedef _List_iterator<_Tp,_Tp&,_Tp*>             iterator;typedef _List_iterator<_Tp,const _Tp&,const _Tp*> const_iterator;typedef _List_iterator<_Tp,_Ref,_Ptr>             _Self;typedef _Tp value_type;typedef _Ptr pointer;typedef _Ref reference;typedef _List_node<_Tp> _Node;//构造函数_List_iterator(_Node* __x) : _List_iterator_base(__x) {}_List_iterator() {}_List_iterator(const iterator& __x) : _List_iterator_base(__x._M_node) {}//以下都是基本操作符的重载,取出节点数据reference operator*() const { return ((_Node*) _M_node)->_M_data; }#ifndef __SGI_STL_NO_ARROW_OPERATORpointer operator->() const { return &(operator*()); }
#endif /* __SGI_STL_NO_ARROW_OPERATOR */_Self& operator++() { this->_M_incr();return *this;}_Self operator++(int) { _Self __tmp = *this;this->_M_incr();return __tmp;}_Self& operator--() { this->_M_decr();return *this;}_Self operator--(int) { _Self __tmp = *this;this->_M_decr();return __tmp;}
};#ifndef __STL_CLASS_PARTIAL_SPECIALIZATION//返回迭代器的类型
inline bidirectional_iterator_tag
iterator_category(const _List_iterator_base&)
{return bidirectional_iterator_tag();
}template <class _Tp, class _Ref, class _Ptr>
inline _Tp*
value_type(const _List_iterator<_Tp, _Ref, _Ptr>&)
{return 0;
}inline ptrdiff_t*
distance_type(const _List_iterator_base&)
{return 0;
}#endif /* __STL_CLASS_PARTIAL_SPECIALIZATION */

list容器的构造函数和析构函数

    这里把list容器的构造函数列出来讲解,使我们对list容器的构造函数进行全面的了解,以便我们对其使用。在以下源码的前面我会总结出list容器的构造函数及其使用方法。

//以下是双向链表list类的定义,分配器_Alloc默认为第二级配置器
template <class _Tp, class _Alloc = __STL_DEFAULT_ALLOCATOR(_Tp) >
class list : protected _List_base<_Tp, _Alloc> { ...
public://**********************************************************************/***********************以下是构造函数**********************************//*******************默认构造函数***************************************explicit list( const Allocator& alloc = Allocator() );//**********************具有初值和大小的构造函数************************explicit list( size_type count,const T& value = T(),const Allocator& alloc = Allocator());list( size_type count,const T& value,const Allocator& alloc = Allocator());//**************只有大小的构造函数**************************************explicit list( size_type count );//************某个范围的值为初始值的构造函数****************************template< class InputIt >list( InputIt first, InputIt last,const Allocator& alloc = Allocator() );//************拷贝构造函数***********************************************list( const list& other );*///**********************************************************************//构造函数//链表的默认构造函数explicit list(const allocator_type& __a = allocator_type()) : _Base(__a) {}list(size_type __n, const _Tp& __value,const allocator_type& __a = allocator_type()): _Base(__a){ insert(begin(), __n, __value); }explicit list(size_type __n): _Base(allocator_type()){ insert(begin(), __n, _Tp()); }#ifdef __STL_MEMBER_TEMPLATES// We don't need any dispatching tricks here, because insert does all of// that anyway.  template <class _InputIterator>list(_InputIterator __first, _InputIterator __last,const allocator_type& __a = allocator_type()): _Base(__a){ insert(begin(), __first, __last); }#else /* __STL_MEMBER_TEMPLATES */list(const _Tp* __first, const _Tp* __last,const allocator_type& __a = allocator_type()): _Base(__a){ this->insert(begin(), __first, __last); }list(const_iterator __first, const_iterator __last,const allocator_type& __a = allocator_type()): _Base(__a){ this->insert(begin(), __first, __last); }#endif /* __STL_MEMBER_TEMPLATES */list(const list<_Tp, _Alloc>& __x) : _Base(__x.get_allocator()){ insert(begin(), __x.begin(), __x.end()); }//拷贝构造函数~list() { }//析构函数//赋值操作list<_Tp, _Alloc>& operator=(const list<_Tp, _Alloc>& __x);//构造函数,析构函数,赋值操作 定义到此结束//*******************************************************************...
};

list容器的成员函数

    list容器的成员函数为我们使用该容器提供了很大的帮助,所以这里对其进行讲解,首先先给出源码的剖析,然后在对其中一些重点的成员函数进行图文讲解;具体源码剖析如下所示:

//以下是双向链表list类的定义,分配器_Alloc默认为第二级配置器
template <class _Tp, class _Alloc = __STL_DEFAULT_ALLOCATOR(_Tp) >
class list : protected _List_base<_Tp, _Alloc> {// requirements:...protected://创建值为x的节点,并返回该节点的地址_Node* _M_create_node(const _Tp& __x){_Node* __p = _M_get_node();//分配一个节点空间__STL_TRY {//把x值赋予指定的地址,即是data值_Construct(&__p->_M_data, __x);}__STL_UNWIND(_M_put_node(__p));return __p;//返回节点地址}//创建默认值的节点_Node* _M_create_node(){_Node* __p = _M_get_node();__STL_TRY {_Construct(&__p->_M_data);}__STL_UNWIND(_M_put_node(__p));return __p;}public://以下是迭代器的定义iterator begin()             { return (_Node*)(_M_node->_M_next); }const_iterator begin() const { return (_Node*)(_M_node->_M_next); }iterator end()             { return _M_node; }const_iterator end() const { return _M_node; }reverse_iterator rbegin() { return reverse_iterator(end()); }const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); }reverse_iterator rend(){ return reverse_iterator(begin()); }const_reverse_iterator rend() const{ return const_reverse_iterator(begin()); }//判断链表是否为空链表bool empty() const { return _M_node->_M_next == _M_node; }//返回链表的大小size_type size() const {size_type __result = 0;//返回两个迭代器之间的距离distance(begin(), end(), __result);//返回链表的元素个数return __result;}size_type max_size() const { return size_type(-1); }//返回第一个节点数据的引用,reference相当于value_type&reference front() { return *begin(); }const_reference front() const { return *begin(); }//返回最后一个节点数据的引用reference back() { return *(--end()); }const_reference back() const { return *(--end()); }//交换链表容器的内容void swap(list<_Tp, _Alloc>& __x) { __STD::swap(_M_node, __x._M_node); }//**********************************************************************//*********************插入节点*****************************************/******************以下是插入节点函数的原型,也是公共接口**************//在指定的位置pos之前插入值为value的数据节点iterator insert( iterator pos, const T& value );iterator insert( const_iterator pos, const T& value );//在指定的位置pos之前插入n个值为value的数据节点void insert( iterator pos, size_type count, const T& value );iterator insert( const_iterator pos, size_type count, const T& value );//在指定的位置pos之前插入[first,last)之间的数据节点template< class InputIt >void insert( iterator pos, InputIt first, InputIt last);template< class InputIt >iterator insert( const_iterator pos, InputIt first, InputIt last );***********************************************************************//**在整个链表的操作中,插入操作是非常重要的,很多成员函数会调用该函数**/
//***********************************************************************//在指定的位置插入初始值为x的节点iterator insert(iterator __position, const _Tp& __x) {//首先创建一个初始值为x的节点,并返回该节点的地址_Node* __tmp = _M_create_node(__x);//调整节点指针,把新节点插入到指定位置__tmp->_M_next = __position._M_node;__tmp->_M_prev = __position._M_node->_M_prev;__position._M_node->_M_prev->_M_next = __tmp;__position._M_node->_M_prev = __tmp;//返回新节点地址return __tmp;}//在指定的位置插入为默认值的节点iterator insert(iterator __position) { return insert(__position, _Tp()); }//在指定位置插入n个初始值为x的节点void insert(iterator __pos, size_type __n, const _Tp& __x){ _M_fill_insert(__pos, __n, __x); }void _M_fill_insert(iterator __pos, size_type __n, const _Tp& __x); #ifdef __STL_MEMBER_TEMPLATES// Check whether it's an integral type.  If so, it's not an iterator.//这里采用__type_traits技术//在指定位置插入指定范围内的数据//首先判断输入迭代器类型_InputIterator是否为整数类型template <class _InputIterator>void insert(iterator __pos, _InputIterator __first, _InputIterator __last) {typedef typename _Is_integer<_InputIterator>::_Integral _Integral;_M_insert_dispatch(__pos, __first, __last, _Integral());}//若输入迭代器类型_InputIterator是为整数类型,调用此函数template<class _Integer>void _M_insert_dispatch(iterator __pos, _Integer __n, _Integer __x,__true_type) {_M_fill_insert(__pos, (size_type) __n, (_Tp) __x);}//若输入迭代器类型_InputIterator是不为整数类型,调用此函数template <class _InputIterator>void _M_insert_dispatch(iterator __pos,_InputIterator __first, _InputIterator __last,__false_type);#else /* __STL_MEMBER_TEMPLATES */void insert(iterator __position, const _Tp* __first, const _Tp* __last);void insert(iterator __position,const_iterator __first, const_iterator __last);
#endif /* __STL_MEMBER_TEMPLATES *///在链表头插入节点void push_front(const _Tp& __x) { insert(begin(), __x); }void push_front() {insert(begin());}//在链表尾插入节点void push_back(const _Tp& __x) { insert(end(), __x); }void push_back() {insert(end());}//***********************************************************//********************在指定位置删除节点*********************//********************以下是删除节点的公共接口***************/************************************************************//删除指定位置pos的节点iterator erase( iterator pos );iterator erase( const_iterator pos );//删除指定范围[first,last)的数据节点iterator erase( iterator first, iterator last );iterator erase( const_iterator first, const_iterator last );************************************************************///***********************************************************//在指定位置position删除节点,并返回直接后继节点的地址iterator erase(iterator __position) {//调整前驱和后继节点的位置_List_node_base* __next_node = __position._M_node->_M_next;_List_node_base* __prev_node = __position._M_node->_M_prev;_Node* __n = (_Node*) __position._M_node;__prev_node->_M_next = __next_node;__next_node->_M_prev = __prev_node;_Destroy(&__n->_M_data);_M_put_node(__n);return iterator((_Node*) __next_node);}//删除两个迭代器之间的节点iterator erase(iterator __first, iterator __last);//清空链表,这里是调用父类的clear()函数void clear() { _Base::clear(); }//调整链表的大小void resize(size_type __new_size, const _Tp& __x);void resize(size_type __new_size) { this->resize(__new_size, _Tp()); }//取出第一个数据节点void pop_front() { erase(begin()); }//取出最后一个数据节点void pop_back() { iterator __tmp = end();erase(--__tmp);}public:// assign(), a generalized assignment member function.  Two// versions: one that takes a count, and one that takes a range.// The range version is a member template, so we dispatch on whether// or not the type is an integer./*********************************************************************//assign()函数的两个版本原型,功能是在已定义的list容器填充值void assign( size_type count, const T& value );template< class InputIt >void assign( InputIt first, InputIt last );//*******************************************************************例子:#include <list>#include <iostream>int main(){std::list<char> characters;//若定义characters时并初始化为字符b,下面的填充操作一样有效//std::list<char>characters(5,'b')characters.assign(5, 'a');for (char c : characters) {std::cout << c << ' ';}return 0;}输出结果:a a a a a*********************************************************************///这里是第一个版本void assign( size_type count, const T& value );void assign(size_type __n, const _Tp& __val) { _M_fill_assign(__n, __val); }//这里为什么要把_M_fill_assign这个函数放在public呢??保护起来不是更好吗??void _M_fill_assign(size_type __n, const _Tp& __val);#ifdef __STL_MEMBER_TEMPLATES//以下是针对assign()函数的第二个版本/*template< class InputIt >void assign( InputIt first, InputIt last );这里有偏特化的现象,判断输入数据类型是否为整数型别*/template <class _InputIterator>void assign(_InputIterator __first, _InputIterator __last) {typedef typename _Is_integer<_InputIterator>::_Integral _Integral;_M_assign_dispatch(__first, __last, _Integral());}//若输入数据类型为整数型别,则派送到此函数template <class _Integer>void _M_assign_dispatch(_Integer __n, _Integer __val, __true_type){ _M_fill_assign((size_type) __n, (_Tp) __val); }//若输入数据类型不是整数型别,则派送到此函数template <class _InputIterator>void _M_assign_dispatch(_InputIterator __first, _InputIterator __last,__false_type);#endif /* __STL_MEMBER_TEMPLATES *///assign()函数定义结束//*****************************************************************protected://把区间[first,last)的节点数据插入到指定节点position之前,position不能在区间内部//这个函数是list类的protected属性,不是公共接口,只为list类成员服务//为下面拼接函数void splice()服务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;}}public://**********************************************************//*******************拼接操作对外接口***********************//把链表拼接到当前链表指定位置position之前/*void splice(const_iterator pos, list& other);//把it在链表other所指的位置拼接到当前链表pos之前,it和pos可指向同一链表void splice(const_iterator pos, list& other, const_iterator it);//把链表other的节点范围[first,last)拼接在当前链表所指定的位置pos之前//[first,last)和pos可指向同一链表void splice(const_iterator pos, list& other,const_iterator first, const_iterator last);*************************************************************///**********************************************************//将链表x拼接到当前链表的指定位置position之前//这里x和*this必须不同,即是两个不同的链表void splice(iterator __position, list& __x) {if (!__x.empty()) this->transfer(__position, __x.begin(), __x.end());}//将i所指向的节点拼接到position所指位置之前//注意:i和position可以指向同一个链表void splice(iterator __position, list&, iterator __i) {iterator __j = __i;++__j;//若i和position指向同一个链表,且指向同一位置//或者i和position指向同一个链表,且就在position的直接前驱位置//针对以上这两种情况,不做任何操作if (__position == __i || __position == __j) return;//否则,进行拼接操作this->transfer(__position, __i, __j);}//将范围[first,last)内所有节点拼接到position所指位置之前//注意:[first,last)和position可指向同一个链表,//但是position不能在[first,last)范围之内void splice(iterator __position, list&, iterator __first, iterator __last) {if (__first != __last) this->transfer(__position, __first, __last);}//以下是成员函数声明,定义在list类外实现//************************************************************//删除链表中值等于value的所有节点void remove(const _Tp& __value);//删除连续重复的元素节点,使之唯一//注意:是连续的重复元素void unique();//合并两个已排序的链表void merge(list& __x);//反转链表容器的内容void reverse();//按升序排序链表内容void sort();#ifdef __STL_MEMBER_TEMPLATEStemplate <class _Predicate> void remove_if(_Predicate);template <class _BinaryPredicate> void unique(_BinaryPredicate);template <class _StrictWeakOrdering> void merge(list&, _StrictWeakOrdering);template <class _StrictWeakOrdering> void sort(_StrictWeakOrdering);
#endif /* __STL_MEMBER_TEMPLATES */
};
    list容器的成员函数中最重要的几个成员函数是插入insert()、擦除erase()、拼接splice()和排序sort()函数;以下利用图文的形式对其进行讲解;首先对插入节点函数进行insert()分析:

    下面的插入函数是在指定的位置插入初始值为value的节点,具体实现见下面源码剖析:

 //*********************插入节点*****************************************/******************以下是插入节点函数的原型,也是公共接口**************//在指定的位置pos之前插入值为value的数据节点iterator insert( iterator pos, const T& value );iterator insert( const_iterator pos, const T& value );//在指定的位置pos之前插入n个值为value的数据节点void insert( iterator pos, size_type count, const T& value );iterator insert( const_iterator pos, size_type count, const T& value );//在指定的位置pos之前插入[first,last)之间的数据节点template< class InputIt >void insert( iterator pos, InputIt first, InputIt last);template< class InputIt >iterator insert( const_iterator pos, InputIt first, InputIt last );***********************************************************************//**在整个链表的操作中,插入操作是非常重要的,很多成员函数会调用该函数**/
//***********************************************************************//在指定的位置插入初始值为x的节点iterator insert(iterator __position, const _Tp& __x) {//首先创建一个初始值为x的节点,并返回该节点的地址_Node* __tmp = _M_create_node(__x);//调整节点指针,把新节点插入到指定位置__tmp->_M_next = __position._M_node;__tmp->_M_prev = __position._M_node->_M_prev;__position._M_node->_M_prev->_M_next = __tmp;__position._M_node->_M_prev = __tmp;//返回新节点地址return __tmp;}
           下面举一个例子对插入函数insert()进行图文分析:假设在以下list链表中节点5之前插入节点9,具体实现见下图步骤:注:图中的箭头旁边的数字表示语句的执行步骤

    第一步:首先初始化节点9,并为其分配节点空间;

    第二步:调整节点5指针方向,使其与节点9连接;

    第三步:调整节点5的前驱结点7指针的方向,使其与节点9连接;

    以下分析的是擦除指定位置的节点,详细见源码剖析:

 //***********************************************************//********************在指定位置删除节点*********************//********************以下是删除节点的公共接口***************/************************************************************//删除指定位置pos的节点iterator erase( iterator pos );iterator erase( const_iterator pos );//删除指定范围[first,last)的数据节点iterator erase( iterator first, iterator last );iterator erase( const_iterator first, const_iterator last );************************************************************///***********************************************************//在指定位置position删除节点,并返回直接后继节点的地址iterator erase(iterator __position) {//调整前驱和后继节点的位置_List_node_base* __next_node = __position._M_node->_M_next;_List_node_base* __prev_node = __position._M_node->_M_prev;_Node* __n = (_Node*) __position._M_node;__prev_node->_M_next = __next_node;__next_node->_M_prev = __prev_node;_Destroy(&__n->_M_data);_M_put_node(__n);return iterator((_Node*) __next_node);}

    下面举一个例子对擦除函数erase()进行图文分析:假设在以下list链表中删除节点5,具体实现见下图步骤:图中的箭头旁边的数字表示语句的执行步骤

    第一步:首先调整待删除节点直接前驱指针,使其指向待删除节点的直接后继节点;

    第二步:调整待删除节点直接后继指针方向,使其指向待删除节点的直接前驱节点;

    第三步:释放待删除节点对象,回收待删除节点内存空;



    以下对迁移操作transfer()进行分析,该函数不是公共接口,属于list容器的保护成员函数,但是它为拼接函数服务,拼接函数的核心就是迁移函数;transfer()splice()函数源代码剖析如下:

protected://把区间[first,last)的节点数据插入到指定节点position之前,position不能在区间内部//这个函数是list类的protected属性,不是公共接口,只为list类成员服务//为下面拼接函数void splice()服务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;}}public://**********************************************************//*******************拼接操作对外接口***********************//把链表拼接到当前链表指定位置position之前/*void splice(const_iterator pos, list& other);//把it在链表other所指的位置拼接到当前链表pos之前,it和pos可指向同一链表void splice(const_iterator pos, list& other, const_iterator it);//把链表other的节点范围[first,last)拼接在当前链表所指定的位置pos之前//[first,last)和pos可指向同一链表void splice(const_iterator pos, list& other,const_iterator first, const_iterator last);*************************************************************///**********************************************************//将链表x拼接到当前链表的指定位置position之前//这里x和*this必须不同,即是两个不同的链表void splice(iterator __position, list& __x) {if (!__x.empty()) this->transfer(__position, __x.begin(), __x.end());}//将i所指向的节点拼接到position所指位置之前//注意:i和position可以指向同一个链表void splice(iterator __position, list&, iterator __i) {iterator __j = __i;++__j;//若i和position指向同一个链表,且指向同一位置//或者i和position指向同一个链表,且就在position的直接前驱位置//针对以上这两种情况,不做任何操作if (__position == __i || __position == __j) return;//否则,进行拼接操作this->transfer(__position, __i, __j);}//将范围[first,last)内所有节点拼接到position所指位置之前//注意:[first,last)和position可指向同一个链表,//但是position不能在[first,last)范围之内void splice(iterator __position, list&, iterator __first, iterator __last) {if (__first != __last) this->transfer(__position, __first, __last);}
    下面用图文对该函数进行分析:注:transfer函数中的每一条语句按顺序对应图中执行步骤;

    下图是执行第一过程Remove[first, last) from its old position流图:


    下图是执行第二过程Splice [first, last) into its new position流图:

   关于list容器的排序算法sort前面博文已经单独对其进行讲解,需要了解的请往前面博文STL源码剖析——list容器的排序算法sort()了解;

list容器的操作符重载

    关于操作符重载具体看源码剖析:
//**************************************************************
//*****************以下是比较运算符操作符重载*******************
//**************************************************************
template <class _Tp, class _Alloc>
inline bool 
operator==(const list<_Tp,_Alloc>& __x, const list<_Tp,_Alloc>& __y)
{typedef typename list<_Tp,_Alloc>::const_iterator const_iterator;const_iterator __end1 = __x.end();const_iterator __end2 = __y.end();const_iterator __i1 = __x.begin();const_iterator __i2 = __y.begin();while (__i1 != __end1 && __i2 != __end2 && *__i1 == *__i2) {++__i1;++__i2;}return __i1 == __end1 && __i2 == __end2;
}template <class _Tp, class _Alloc>
inline bool operator<(const list<_Tp,_Alloc>& __x,const list<_Tp,_Alloc>& __y)
{return lexicographical_compare(__x.begin(), __x.end(),__y.begin(), __y.end());
}#ifdef __STL_FUNCTION_TMPL_PARTIAL_ORDERtemplate <class _Tp, class _Alloc>
inline bool operator!=(const list<_Tp,_Alloc>& __x,const list<_Tp,_Alloc>& __y) {return !(__x == __y);
}template <class _Tp, class _Alloc>
inline bool operator>(const list<_Tp,_Alloc>& __x,const list<_Tp,_Alloc>& __y) {return __y < __x;
}template <class _Tp, class _Alloc>
inline bool operator<=(const list<_Tp,_Alloc>& __x,const list<_Tp,_Alloc>& __y) {return !(__y < __x);
}template <class _Tp, class _Alloc>
inline bool operator>=(const list<_Tp,_Alloc>& __x,const list<_Tp,_Alloc>& __y) {return !(__x < __y);
}//交换两个链表内容
template <class _Tp, class _Alloc>
inline void 
swap(list<_Tp, _Alloc>& __x, list<_Tp, _Alloc>& __y)
{__x.swap(__y);
}#endif /* __STL_FUNCTION_TMPL_PARTIAL_ORDER */
//操作符重载结束
//**************************************************************

list容器完整源码剖析

       list容器完成源码剖析:
//以下是list链表节点的数据结构
struct _List_node_base {_List_node_base* _M_next;//指向直接后继节点_List_node_base* _M_prev;//指向直接前驱节点
};template <class _Tp>
struct _List_node : public _List_node_base {_Tp _M_data;//节点存储的数据
};//以下是链表List_iterator_base的迭代器
struct _List_iterator_base {//数据类型typedef size_t                     size_type;typedef ptrdiff_t                  difference_type;//list迭代器的类型是双向迭代器bidirectional_iteratortypedef bidirectional_iterator_tag iterator_category;//定义指向链表节点的指针_List_node_base* _M_node;//构造函数_List_iterator_base(_List_node_base* __x) : _M_node(__x) {}_List_iterator_base() {}//更新节点指针,指向直接前驱或直接后继节点void _M_incr() { _M_node = _M_node->_M_next; }void _M_decr() { _M_node = _M_node->_M_prev; }//操作符重载bool operator==(const _List_iterator_base& __x) const {return _M_node == __x._M_node;}bool operator!=(const _List_iterator_base& __x) const {return _M_node != __x._M_node;}
};  //以下是链表List_iterator的迭代器
template<class _Tp, class _Ref, class _Ptr>
struct _List_iterator : public _List_iterator_base {typedef _List_iterator<_Tp,_Tp&,_Tp*>             iterator;typedef _List_iterator<_Tp,const _Tp&,const _Tp*> const_iterator;typedef _List_iterator<_Tp,_Ref,_Ptr>             _Self;typedef _Tp value_type;typedef _Ptr pointer;typedef _Ref reference;typedef _List_node<_Tp> _Node;//构造函数_List_iterator(_Node* __x) : _List_iterator_base(__x) {}_List_iterator() {}_List_iterator(const iterator& __x) : _List_iterator_base(__x._M_node) {}//以下都是基本操作符的重载,取出节点数据reference operator*() const { return ((_Node*) _M_node)->_M_data; }#ifndef __SGI_STL_NO_ARROW_OPERATORpointer operator->() const { return &(operator*()); }
#endif /* __SGI_STL_NO_ARROW_OPERATOR */_Self& operator++() { this->_M_incr();return *this;}_Self operator++(int) { _Self __tmp = *this;this->_M_incr();return __tmp;}_Self& operator--() { this->_M_decr();return *this;}_Self operator--(int) { _Self __tmp = *this;this->_M_decr();return __tmp;}
};#ifndef __STL_CLASS_PARTIAL_SPECIALIZATION//返回迭代器的类型
inline bidirectional_iterator_tag
iterator_category(const _List_iterator_base&)
{return bidirectional_iterator_tag();
}template <class _Tp, class _Ref, class _Ptr>
inline _Tp*
value_type(const _List_iterator<_Tp, _Ref, _Ptr>&)
{return 0;
}inline ptrdiff_t*
distance_type(const _List_iterator_base&)
{return 0;
}#endif /* __STL_CLASS_PARTIAL_SPECIALIZATION */// Base class that encapsulates details of allocators.  Three cases:
// an ordinary standard-conforming allocator, a standard-conforming
// allocator with no non-static data, and an SGI-style allocator.
// This complexity is necessary only because we're worrying about backward
// compatibility and because we want to avoid wasting storage on an 
// allocator instance if it isn't necessary.#ifdef __STL_USE_STD_ALLOCATORS// Base for general standard-conforming allocators.
template <class _Tp, class _Allocator, bool _IsStatic>
class _List_alloc_base {
public:typedef typename _Alloc_traits<_Tp, _Allocator>::allocator_typeallocator_type;//返回节点配置器allocator_type get_allocator() const { return _Node_allocator; }_List_alloc_base(const allocator_type& __a) : _Node_allocator(__a) {}protected:_List_node<_Tp>* _M_get_node(){ return _Node_allocator.allocate(1); }void _M_put_node(_List_node<_Tp>* __p){ _Node_allocator.deallocate(__p, 1); }protected:typename _Alloc_traits<_List_node<_Tp>, _Allocator>::allocator_type_Node_allocator;_List_node<_Tp>* _M_node;
};// Specialization for instanceless allocators.
//instanceless分配器偏特化版
template <class _Tp, class _Allocator>
class _List_alloc_base<_Tp, _Allocator, true> {
public://定义分配器类型typedef typename _Alloc_traits<_Tp, _Allocator>::allocator_typeallocator_type;//返回节点配置器allocator_type get_allocator() const { return allocator_type(); }//构造函数_List_alloc_base(const allocator_type&) {}protected:typedef typename _Alloc_traits<_List_node<_Tp>, _Allocator>::_Alloc_type_Alloc_type;//分配一个节点空间_List_node<_Tp>* _M_get_node() { return _Alloc_type::allocate(1); }//回收一个节点空间void _M_put_node(_List_node<_Tp>* __p) { _Alloc_type::deallocate(__p, 1); }protected://定义节点指针_List_node<_Tp>* _M_node;
};template <class _Tp, class _Alloc>
class _List_base : public _List_alloc_base<_Tp, _Alloc,_Alloc_traits<_Tp, _Alloc>::_S_instanceless>
{
public:typedef _List_alloc_base<_Tp, _Alloc,_Alloc_traits<_Tp, _Alloc>::_S_instanceless>_Base; //allocator_type迭代器类型typedef typename _Base::allocator_type allocator_type;//构造函数_List_base(const allocator_type& __a) : _Base(__a) {_M_node = _M_get_node();//分配一个节点空间_M_node->_M_next = _M_node;//_M_node->_M_prev = _M_node;}//析构函数~_List_base() {clear();//清空链表_M_put_node(_M_node);//回收一个节点内存空间}void clear();//清空链表
};#else /* __STL_USE_STD_ALLOCATORS */template <class _Tp, class _Alloc>
class _List_base 
{
public:typedef _Alloc allocator_type;//获得分配器类型allocator_type get_allocator() const { return allocator_type(); }//构造函数_List_base(const allocator_type&) {_M_node = _M_get_node();//分配一个节点空间//节点前驱和后继指针指向自己,表示是一个空链表_M_node->_M_next = _M_node;_M_node->_M_prev = _M_node;}//析构函数~_List_base() {clear();//清空链表_M_put_node(_M_node);//回收一个节点内存空间}void clear();//清空链表protected://迭代器类型typedef simple_alloc<_List_node<_Tp>, _Alloc> _Alloc_type;//分配一个节点内存空间_List_node<_Tp>* _M_get_node() { return _Alloc_type::allocate(1); }//回收一个节点内存空间void _M_put_node(_List_node<_Tp>* __p) { _Alloc_type::deallocate(__p, 1); } protected:_List_node<_Tp>* _M_node;//链表的节点指针
};#endif /* __STL_USE_STD_ALLOCATORS *///clear()函数的实现,即清空链表
template <class _Tp, class _Alloc>
void 
_List_base<_Tp,_Alloc>::clear() 
{//选取_M_node->_M_next作为当前节点_List_node<_Tp>* __cur = (_List_node<_Tp>*) _M_node->_M_next;while (__cur != _M_node) {//遍历每一个节点_List_node<_Tp>* __tmp = __cur;//设置一个节点临时别名__cur = (_List_node<_Tp>*) __cur->_M_next;//指向下一个节点_Destroy(&__tmp->_M_data);//析构数据对象_M_put_node(__tmp);//回收节点tmp指向的内存空间}//空链表,即前驱和后继指针都指向自己_M_node->_M_next = _M_node;_M_node->_M_prev = _M_node;
}//以下是双向链表list类的定义,分配器_Alloc默认为第二级配置器
template <class _Tp, class _Alloc = __STL_DEFAULT_ALLOCATOR(_Tp) >
class list : protected _List_base<_Tp, _Alloc> {// requirements:__STL_CLASS_REQUIRES(_Tp, _Assignable);typedef _List_base<_Tp, _Alloc> _Base;
protected:typedef void* _Void_pointer;//定义指针类型public: //以下是内嵌型别typedef _Tp value_type;typedef value_type* pointer;typedef const value_type* const_pointer;typedef value_type& reference;typedef const value_type& const_reference;typedef _List_node<_Tp> _Node;typedef size_t size_type;typedef ptrdiff_t difference_type;typedef typename _Base::allocator_type allocator_type;//分配器类型allocator_type get_allocator() const { return _Base::get_allocator(); }public://迭代器的类型typedef _List_iterator<_Tp,_Tp&,_Tp*>             iterator;typedef _List_iterator<_Tp,const _Tp&,const _Tp*> const_iterator;#ifdef __STL_CLASS_PARTIAL_SPECIALIZATIONtypedef reverse_iterator<const_iterator> const_reverse_iterator;typedef reverse_iterator<iterator>       reverse_iterator;
#else /* __STL_CLASS_PARTIAL_SPECIALIZATION */typedef reverse_bidirectional_iterator<const_iterator,value_type,const_reference,difference_type>const_reverse_iterator;typedef reverse_bidirectional_iterator<iterator,value_type,reference,difference_type>reverse_iterator; 
#endif /* __STL_CLASS_PARTIAL_SPECIALIZATION */protected:
#ifdef __STL_HAS_NAMESPACESusing _Base::_M_node;using _Base::_M_put_node;using _Base::_M_get_node;
#endif /* __STL_HAS_NAMESPACES */protected://创建值为x的节点,并返回该节点的地址_Node* _M_create_node(const _Tp& __x){_Node* __p = _M_get_node();//分配一个节点空间__STL_TRY {//把x值赋予指定的地址,即是data值_Construct(&__p->_M_data, __x);}__STL_UNWIND(_M_put_node(__p));return __p;//返回节点地址}//创建默认值的节点_Node* _M_create_node(){_Node* __p = _M_get_node();__STL_TRY {_Construct(&__p->_M_data);}__STL_UNWIND(_M_put_node(__p));return __p;}public://以下是迭代器的定义iterator begin()             { return (_Node*)(_M_node->_M_next); }const_iterator begin() const { return (_Node*)(_M_node->_M_next); }iterator end()             { return _M_node; }const_iterator end() const { return _M_node; }reverse_iterator rbegin() { return reverse_iterator(end()); }const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); }reverse_iterator rend(){ return reverse_iterator(begin()); }const_reverse_iterator rend() const{ return const_reverse_iterator(begin()); }//判断链表是否为空链表bool empty() const { return _M_node->_M_next == _M_node; }//返回链表的大小size_type size() const {size_type __result = 0;//返回两个迭代器之间的距离distance(begin(), end(), __result);//返回链表的元素个数return __result;}size_type max_size() const { return size_type(-1); }//返回第一个节点数据的引用,reference相当于value_type&reference front() { return *begin(); }const_reference front() const { return *begin(); }//返回最后一个节点数据的引用reference back() { return *(--end()); }const_reference back() const { return *(--end()); }//交换链表容器的内容void swap(list<_Tp, _Alloc>& __x) { __STD::swap(_M_node, __x._M_node); }//**********************************************************************//*********************插入节点*****************************************/******************以下是插入节点函数的原型,也是公共接口**************//在指定的位置pos之前插入值为value的数据节点iterator insert( iterator pos, const T& value );iterator insert( const_iterator pos, const T& value );//在指定的位置pos之前插入n个值为value的数据节点void insert( iterator pos, size_type count, const T& value );iterator insert( const_iterator pos, size_type count, const T& value );//在指定的位置pos之前插入[first,last)之间的数据节点template< class InputIt >void insert( iterator pos, InputIt first, InputIt last);template< class InputIt >iterator insert( const_iterator pos, InputIt first, InputIt last );***********************************************************************//**在整个链表的操作中,插入操作是非常重要的,很多成员函数会调用该函数**/
//***********************************************************************//在指定的位置插入初始值为x的节点iterator insert(iterator __position, const _Tp& __x) {//首先创建一个初始值为x的节点,并返回该节点的地址_Node* __tmp = _M_create_node(__x);//调整节点指针,把新节点插入到指定位置__tmp->_M_next = __position._M_node;__tmp->_M_prev = __position._M_node->_M_prev;__position._M_node->_M_prev->_M_next = __tmp;__position._M_node->_M_prev = __tmp;//返回新节点地址return __tmp;}//在指定的位置插入为默认值的节点iterator insert(iterator __position) { return insert(__position, _Tp()); }//在指定位置插入n个初始值为x的节点void insert(iterator __pos, size_type __n, const _Tp& __x){ _M_fill_insert(__pos, __n, __x); }void _M_fill_insert(iterator __pos, size_type __n, const _Tp& __x); #ifdef __STL_MEMBER_TEMPLATES// Check whether it's an integral type.  If so, it's not an iterator.//这里采用__type_traits技术//在指定位置插入指定范围内的数据//首先判断输入迭代器类型_InputIterator是否为整数类型template <class _InputIterator>void insert(iterator __pos, _InputIterator __first, _InputIterator __last) {typedef typename _Is_integer<_InputIterator>::_Integral _Integral;_M_insert_dispatch(__pos, __first, __last, _Integral());}//若输入迭代器类型_InputIterator是为整数类型,调用此函数template<class _Integer>void _M_insert_dispatch(iterator __pos, _Integer __n, _Integer __x,__true_type) {_M_fill_insert(__pos, (size_type) __n, (_Tp) __x);}//若输入迭代器类型_InputIterator是不为整数类型,调用此函数template <class _InputIterator>void _M_insert_dispatch(iterator __pos,_InputIterator __first, _InputIterator __last,__false_type);#else /* __STL_MEMBER_TEMPLATES */void insert(iterator __position, const _Tp* __first, const _Tp* __last);void insert(iterator __position,const_iterator __first, const_iterator __last);
#endif /* __STL_MEMBER_TEMPLATES *///在链表头插入节点void push_front(const _Tp& __x) { insert(begin(), __x); }void push_front() {insert(begin());}//在链表尾插入节点void push_back(const _Tp& __x) { insert(end(), __x); }void push_back() {insert(end());}//***********************************************************//********************在指定位置删除节点*********************//********************以下是删除节点的公共接口***************/************************************************************//删除指定位置pos的节点iterator erase( iterator pos );iterator erase( const_iterator pos );//删除指定范围[first,last)的数据节点iterator erase( iterator first, iterator last );iterator erase( const_iterator first, const_iterator last );************************************************************///***********************************************************//在指定位置position删除节点,并返回直接后继节点的地址iterator erase(iterator __position) {//调整前驱和后继节点的位置_List_node_base* __next_node = __position._M_node->_M_next;_List_node_base* __prev_node = __position._M_node->_M_prev;_Node* __n = (_Node*) __position._M_node;__prev_node->_M_next = __next_node;__next_node->_M_prev = __prev_node;_Destroy(&__n->_M_data);_M_put_node(__n);return iterator((_Node*) __next_node);}//删除两个迭代器之间的节点iterator erase(iterator __first, iterator __last);//清空链表,这里是调用父类的clear()函数void clear() { _Base::clear(); }//调整链表的大小void resize(size_type __new_size, const _Tp& __x);void resize(size_type __new_size) { this->resize(__new_size, _Tp()); }//取出第一个数据节点void pop_front() { erase(begin()); }//取出最后一个数据节点void pop_back() { iterator __tmp = end();erase(--__tmp);}//**********************************************************************/***********************以下是构造函数**********************************//*******************默认构造函数***************************************explicit list( const Allocator& alloc = Allocator() );//**********************具有初值和大小的构造函数************************explicit list( size_type count,const T& value = T(),const Allocator& alloc = Allocator());list( size_type count,const T& value,const Allocator& alloc = Allocator());//**************只有大小的构造函数**************************************explicit list( size_type count );//************某个范围的值为初始值的构造函数****************************template< class InputIt >list( InputIt first, InputIt last,const Allocator& alloc = Allocator() );//************拷贝构造函数***********************************************list( const list& other );*///**********************************************************************//构造函数//链表的默认构造函数explicit list(const allocator_type& __a = allocator_type()) : _Base(__a) {}list(size_type __n, const _Tp& __value,const allocator_type& __a = allocator_type()): _Base(__a){ insert(begin(), __n, __value); }explicit list(size_type __n): _Base(allocator_type()){ insert(begin(), __n, _Tp()); }#ifdef __STL_MEMBER_TEMPLATES// We don't need any dispatching tricks here, because insert does all of// that anyway.  template <class _InputIterator>list(_InputIterator __first, _InputIterator __last,const allocator_type& __a = allocator_type()): _Base(__a){ insert(begin(), __first, __last); }#else /* __STL_MEMBER_TEMPLATES */list(const _Tp* __first, const _Tp* __last,const allocator_type& __a = allocator_type()): _Base(__a){ this->insert(begin(), __first, __last); }list(const_iterator __first, const_iterator __last,const allocator_type& __a = allocator_type()): _Base(__a){ this->insert(begin(), __first, __last); }#endif /* __STL_MEMBER_TEMPLATES */list(const list<_Tp, _Alloc>& __x) : _Base(__x.get_allocator()){ insert(begin(), __x.begin(), __x.end()); }//拷贝构造函数~list() { }//析构函数//赋值操作list<_Tp, _Alloc>& operator=(const list<_Tp, _Alloc>& __x);//构造函数,析构函数,赋值操作 定义到此结束//*******************************************************************public:// assign(), a generalized assignment member function.  Two// versions: one that takes a count, and one that takes a range.// The range version is a member template, so we dispatch on whether// or not the type is an integer./*********************************************************************//assign()函数的两个版本原型,功能是在已定义的list容器填充值void assign( size_type count, const T& value );template< class InputIt >void assign( InputIt first, InputIt last );//*******************************************************************例子:#include <list>#include <iostream>int main(){std::list<char> characters;//若定义characters时并初始化为字符b,下面的填充操作一样有效//std::list<char>characters(5,'b')characters.assign(5, 'a');for (char c : characters) {std::cout << c << ' ';}return 0;}输出结果:a a a a a*********************************************************************///这里是第一个版本void assign( size_type count, const T& value );void assign(size_type __n, const _Tp& __val) { _M_fill_assign(__n, __val); }//这里为什么要把_M_fill_assign这个函数放在public呢??保护起来不是更好吗??void _M_fill_assign(size_type __n, const _Tp& __val);#ifdef __STL_MEMBER_TEMPLATES//以下是针对assign()函数的第二个版本/*template< class InputIt >void assign( InputIt first, InputIt last );这里有偏特化的现象,判断输入数据类型是否为整数型别*/template <class _InputIterator>void assign(_InputIterator __first, _InputIterator __last) {typedef typename _Is_integer<_InputIterator>::_Integral _Integral;_M_assign_dispatch(__first, __last, _Integral());}//若输入数据类型为整数型别,则派送到此函数template <class _Integer>void _M_assign_dispatch(_Integer __n, _Integer __val, __true_type){ _M_fill_assign((size_type) __n, (_Tp) __val); }//若输入数据类型不是整数型别,则派送到此函数template <class _InputIterator>void _M_assign_dispatch(_InputIterator __first, _InputIterator __last,__false_type);#endif /* __STL_MEMBER_TEMPLATES *///assign()函数定义结束//*****************************************************************protected://把区间[first,last)的节点数据插入到指定节点position之前,position不能在区间内部//这个函数是list类的protected属性,不是公共接口,只为list类成员服务//为下面拼接函数void splice()服务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;}}public://**********************************************************//*******************拼接操作对外接口***********************//把链表拼接到当前链表指定位置position之前/*void splice(const_iterator pos, list& other);//把it在链表other所指的位置拼接到当前链表pos之前,it和pos可指向同一链表void splice(const_iterator pos, list& other, const_iterator it);//把链表other的节点范围[first,last)拼接在当前链表所指定的位置pos之前//[first,last)和pos可指向同一链表void splice(const_iterator pos, list& other,const_iterator first, const_iterator last);*************************************************************///**********************************************************//将链表x拼接到当前链表的指定位置position之前//这里x和*this必须不同,即是两个不同的链表void splice(iterator __position, list& __x) {if (!__x.empty()) this->transfer(__position, __x.begin(), __x.end());}//将i所指向的节点拼接到position所指位置之前//注意:i和position可以指向同一个链表void splice(iterator __position, list&, iterator __i) {iterator __j = __i;++__j;//若i和position指向同一个链表,且指向同一位置//或者i和position指向同一个链表,且就在position的直接前驱位置//针对以上这两种情况,不做任何操作if (__position == __i || __position == __j) return;//否则,进行拼接操作this->transfer(__position, __i, __j);}//将范围[first,last)内所有节点拼接到position所指位置之前//注意:[first,last)和position可指向同一个链表,//但是position不能在[first,last)范围之内void splice(iterator __position, list&, iterator __first, iterator __last) {if (__first != __last) this->transfer(__position, __first, __last);}//以下是成员函数声明,定义在list类外实现//************************************************************//删除链表中值等于value的所有节点void remove(const _Tp& __value);//删除连续重复的元素节点,使之唯一//注意:是连续的重复元素void unique();//合并两个已排序的链表void merge(list& __x);//反转链表容器的内容void reverse();//按升序排序链表内容void sort();#ifdef __STL_MEMBER_TEMPLATEStemplate <class _Predicate> void remove_if(_Predicate);template <class _BinaryPredicate> void unique(_BinaryPredicate);template <class _StrictWeakOrdering> void merge(list&, _StrictWeakOrdering);template <class _StrictWeakOrdering> void sort(_StrictWeakOrdering);
#endif /* __STL_MEMBER_TEMPLATES */
};
//list定义结束
//**************************************************************//**************************************************************
//*****************以下是比较运算符操作符重载*******************
//**************************************************************
template <class _Tp, class _Alloc>
inline bool 
operator==(const list<_Tp,_Alloc>& __x, const list<_Tp,_Alloc>& __y)
{typedef typename list<_Tp,_Alloc>::const_iterator const_iterator;const_iterator __end1 = __x.end();const_iterator __end2 = __y.end();const_iterator __i1 = __x.begin();const_iterator __i2 = __y.begin();while (__i1 != __end1 && __i2 != __end2 && *__i1 == *__i2) {++__i1;++__i2;}return __i1 == __end1 && __i2 == __end2;
}template <class _Tp, class _Alloc>
inline bool operator<(const list<_Tp,_Alloc>& __x,const list<_Tp,_Alloc>& __y)
{return lexicographical_compare(__x.begin(), __x.end(),__y.begin(), __y.end());
}#ifdef __STL_FUNCTION_TMPL_PARTIAL_ORDERtemplate <class _Tp, class _Alloc>
inline bool operator!=(const list<_Tp,_Alloc>& __x,const list<_Tp,_Alloc>& __y) {return !(__x == __y);
}template <class _Tp, class _Alloc>
inline bool operator>(const list<_Tp,_Alloc>& __x,const list<_Tp,_Alloc>& __y) {return __y < __x;
}template <class _Tp, class _Alloc>
inline bool operator<=(const list<_Tp,_Alloc>& __x,const list<_Tp,_Alloc>& __y) {return !(__y < __x);
}template <class _Tp, class _Alloc>
inline bool operator>=(const list<_Tp,_Alloc>& __x,const list<_Tp,_Alloc>& __y) {return !(__x < __y);
}//交换两个链表内容
template <class _Tp, class _Alloc>
inline void 
swap(list<_Tp, _Alloc>& __x, list<_Tp, _Alloc>& __y)
{__x.swap(__y);
}#endif /* __STL_FUNCTION_TMPL_PARTIAL_ORDER */
//操作符重载结束
//**************************************************************//以下是list类成员函数的具体定义
//**************************************************************
#ifdef __STL_MEMBER_TEMPLATEStemplate <class _Tp, class _Alloc> template <class _InputIter>
void 
list<_Tp, _Alloc>::_M_insert_dispatch(iterator __position,_InputIter __first, _InputIter __last,__false_type)
{for ( ; __first != __last; ++__first)//遍历范围[first,last)insert(__position, *__first);//一个一个节点插入
}#else /* __STL_MEMBER_TEMPLATES */template <class _Tp, class _Alloc>
void 
list<_Tp, _Alloc>::insert(iterator __position, const _Tp* __first, const _Tp* __last)
{for ( ; __first != __last; ++__first)//遍历范围[first,last)insert(__position, *__first);//一个一个节点插入
}template <class _Tp, class _Alloc>
void 
list<_Tp, _Alloc>::insert(iterator __position,const_iterator __first, const_iterator __last)
{for ( ; __first != __last; ++__first)//遍历范围[first,last)insert(__position, *__first);//一个一个节点插入
}#endif /* __STL_MEMBER_TEMPLATES */template <class _Tp, class _Alloc>
void 
list<_Tp, _Alloc>::_M_fill_insert(iterator __position,size_type __n, const _Tp& __x)
{for ( ; __n > 0; --__n)//插入n个节点insert(__position, __x);//在position之前插入x节点
}template <class _Tp, class _Alloc>
typename list<_Tp,_Alloc>::iterator list<_Tp, _Alloc>::erase(iterator __first, iterator __last)
{while (__first != __last)//遍历范围[first,last)erase(__first++);//一个一个节点删除return __last;
}//重新调整容器的大小
template <class _Tp, class _Alloc>
void list<_Tp, _Alloc>::resize(size_type __new_size, const _Tp& __x)
{iterator __i = begin();size_type __len = 0;//表示容器的原始大小for ( ; __i != end() && __len < __new_size; ++__i, ++__len);if (__len == __new_size)//若容器新的长度比原来的小,则擦除多余的元素erase(__i, end());else//若容器新的长度比原来的大,则把其初始化为x值   // __i == end()insert(end(), __new_size - __len, __x);
}//赋值操作
template <class _Tp, class _Alloc>
list<_Tp, _Alloc>& list<_Tp, _Alloc>::operator=(const list<_Tp, _Alloc>& __x)
{if (this != &__x) {iterator __first1 = begin();iterator __last1 = end();const_iterator __first2 = __x.begin();const_iterator __last2 = __x.end();while (__first1 != __last1 && __first2 != __last2) *__first1++ = *__first2++;if (__first2 == __last2)//若当前容器的大小大于x容器大小erase(__first1, __last1);//则擦除多余部分else//若当前容器大小小于x容器大小,则把x容器剩下的数据插入到当前容器尾insert(__last1, __first2, __last2);//上面if语句里面的语句可以用下面代替/*clear();this->assign(__x.begin(),__x.end());*/}return *this;
}//在已定义list容器中填充n个初始值为val的节点
template <class _Tp, class _Alloc>
void list<_Tp, _Alloc>::_M_fill_assign(size_type __n, const _Tp& __val) {iterator __i = begin();for ( ; __i != end() && __n > 0; ++__i, --__n)*__i = __val;if (__n > 0)//若容器大小不够存储n个节点,则使用插入函数insert(end(), __n, __val);else//若容器原来的数据大小比n大,则擦除多余的数据erase(__i, end());//注:个人认为该函数也可以这样实现://首先清空容器原来的内容//然后在容器插入n个值为val的数据节点/*_Tp tmp = __val;clear();insert(begin(),__n,__val);*/
}#ifdef __STL_MEMBER_TEMPLATES//若输入数据类型不是整数型别时,assign(_InputIter __first, _InputIter __last)调用该函数
//在[first,last)实现填充数值操作
template <class _Tp, class _Alloc> template <class _InputIter>
void
list<_Tp, _Alloc>::_M_assign_dispatch(_InputIter __first2, _InputIter __last2,__false_type)
{//获取原始容器的大小iterator __first1 = begin();iterator __last1 = end();//若原始容器和[first2,last2)大小不为0或1,则进行赋值操作for ( ; __first1 != __last1 && __first2 != __last2; ++__first1, ++__first2)*__first1 = *__first2;if (__first2 == __last2)//若原始容器的大小比[first2,last2)大erase(__first1, __last1);else//若原始容器的大小比[first2,last2)小insert(__last1, __first2, __last2);
}#endif /* __STL_MEMBER_TEMPLATES *///删除容器中值为value的所有数据节点
template <class _Tp, class _Alloc>
void list<_Tp, _Alloc>::remove(const _Tp& __value)
{iterator __first = begin();iterator __last = end();while (__first != __last) {//遍历整个容器iterator __next = __first;++__next;if (*__first == __value) erase(__first);//若存在该值,则擦除__first = __next;//继续查找,直到first == last}
}//
template <class _Tp, class _Alloc>
void list<_Tp, _Alloc>::unique()
{iterator __first = begin();iterator __last = end();if (__first == __last) return;//若为空容器,则退出iterator __next = __first;while (++__next != __last) {//若容器大小大于1,进入while循环if (*__first == *__next)//若相邻元素相同erase(__next);//则擦除else//否则,查找下一节点__first = __next;__next = __first;}
}//合并两个已排序的链表,合并后的链表仍然是有序的
template <class _Tp, class _Alloc>
void list<_Tp, _Alloc>::merge(list<_Tp, _Alloc>& __x)
{iterator __first1 = begin();iterator __last1 = end();iterator __first2 = __x.begin();iterator __last2 = __x.end();while (__first1 != __last1 && __first2 != __last2)if (*__first2 < *__first1) {iterator __next = __first2;transfer(__first1, __first2, ++__next);//把first2拼接在first1之前__first2 = __next;}else++__first1;//若链表x比当前链表长,则把剩余的数据节点拼接到当前链表的尾端if (__first2 != __last2) transfer(__last1, __first2, __last2);
}inline void __List_base_reverse(_List_node_base* __p)
{_List_node_base* __tmp = __p;do {__STD::swap(__tmp->_M_next, __tmp->_M_prev);//交换指针所指的节点地址__tmp = __tmp->_M_prev;     // Old next node is now prev.} while (__tmp != __p);
}//把当前链表逆序
template <class _Tp, class _Alloc>
inline void list<_Tp, _Alloc>::reverse() 
{__List_base_reverse(this->_M_node);
}    //按升序进行排序,list链表的迭代器访问时双向迭代器
//因为STL的排序算法函数sort()是接受随机访问迭代器,在这里并不适合
template <class _Tp, class _Alloc>
void list<_Tp, _Alloc>::sort()
{// Do nothing if the list has length 0 or 1.if (_M_node->_M_next != _M_node && _M_node->_M_next->_M_next != _M_node) {list<_Tp, _Alloc> __carry;//carry链表起到搬运的作用//counter链表是中间存储作用/**其中对于counter[i]里面最多的存储数据为2^(i+1)个节点*若超出则向高位进位即counter[i+1]*/list<_Tp, _Alloc> __counter[64];int __fill = 0;while (!empty()) {//若不是空链表//第一步:__carry.splice(__carry.begin(), *this, begin());//把当前链表的第一个节点放在carry链表头int __i = 0;while(__i < __fill && !__counter[__i].empty()) {//第二步:__counter[__i].merge(__carry);//把链表carry合并到counter[i]//第三步:__carry.swap(__counter[__i++]);//交换链表carry和counter[i]内容}//第四步:__carry.swap(__counter[__i]);//交换链表carry和counter[i]内容         //第五步:if (__i == __fill) ++__fill;} for (int __i = 1; __i < __fill; ++__i)//第六步:__counter[__i].merge(__counter[__i-1]);//把低位不满足进位的剩余数据全部有序的合并到上一位//第七步:swap(__counter[__fill-1]);//最后把已排序好的链表内容交换到当前链表}
}#ifdef __STL_MEMBER_TEMPLATEStemplate <class _Tp, class _Alloc> template <class _Predicate>
void list<_Tp, _Alloc>::remove_if(_Predicate __pred)
{iterator __first = begin();iterator __last = end();while (__first != __last) {iterator __next = __first;++__next;if (__pred(*__first)) erase(__first);__first = __next;}
}template <class _Tp, class _Alloc> template <class _BinaryPredicate>
void list<_Tp, _Alloc>::unique(_BinaryPredicate __binary_pred)
{iterator __first = begin();iterator __last = end();if (__first == __last) return;iterator __next = __first;while (++__next != __last) {if (__binary_pred(*__first, *__next))erase(__next);else__first = __next;__next = __first;}
}template <class _Tp, class _Alloc> template <class _StrictWeakOrdering>
void list<_Tp, _Alloc>::merge(list<_Tp, _Alloc>& __x,_StrictWeakOrdering __comp)
{iterator __first1 = begin();iterator __last1 = end();iterator __first2 = __x.begin();iterator __last2 = __x.end();while (__first1 != __last1 && __first2 != __last2)if (__comp(*__first2, *__first1)) {iterator __next = __first2;transfer(__first1, __first2, ++__next);__first2 = __next;}else++__first1;if (__first2 != __last2) transfer(__last1, __first2, __last2);
}template <class _Tp, class _Alloc> template <class _StrictWeakOrdering>
void list<_Tp, _Alloc>::sort(_StrictWeakOrdering __comp)
{// Do nothing if the list has length 0 or 1.if (_M_node->_M_next != _M_node && _M_node->_M_next->_M_next != _M_node) {list<_Tp, _Alloc> __carry;list<_Tp, _Alloc> __counter[64];int __fill = 0;while (!empty()) {__carry.splice(__carry.begin(), *this, begin());int __i = 0;while(__i < __fill && !__counter[__i].empty()) {__counter[__i].merge(__carry, __comp);__carry.swap(__counter[__i++]);}__carry.swap(__counter[__i]);         if (__i == __fill) ++__fill;} for (int __i = 1; __i < __fill; ++__i) __counter[__i].merge(__counter[__i-1], __comp);swap(__counter[__fill-1]);}
}#endif /* __STL_MEMBER_TEMPLATES */#if defined(__sgi) && !defined(__GNUC__) && (_MIPS_SIM != _MIPS_SIM_ABI32)
#pragma reset woff 1174
#pragma reset woff 1375
#endif__STL_END_NAMESPACE #endif /* __SGI_STL_INTERNAL_LIST_H */// Local Variables:
// mode:C++
// End:
    参考资料:
      《STL源码剖析》侯捷
      STL笔记之list
      STL源码剖析--stl_list.h
查看全文
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

相关文章

  1. Linux 安装PyCharm

    安装PyCharm 1、准备内容:需要有一个PyCharm在Linux下的安装包 2、解压缩安装包 解压到某一个常用的软件目录中 tar -zxvf Pycharm..gz -C 选择解压的目录 如:在/usr/local 中创建一个目录 pycharm 解压tar -zxvf Pycharm..gz -C /usr/local/pycharm 3、可以在解压完成的…...

    2024/4/12 16:24:17
  2. 【oracle】for update和for update nowait的用法

    for update是用来上锁的,在commit或rollback之后释放锁。 例如: select * from stu for update; 该语句对取出的所有记录行进行锁定,其他会话访问该记录行会被挂起等待(包括select语句)。如果要避免被挂起等待,可以使用for update nowait,这样一旦访问的数据已经被上锁,…...

    2024/4/12 16:24:07
  3. 模块化JavaScript设计模式(一)

    在可扩展JavaScript的世界里,如果我们说一个应用程序是模块化(modular)的,那么通常意味着它是由一系列存储于模块中的高度解耦,不同的功能片段组成。在可能的情况下,通过一处依赖性,松耦合可以使应用程序的可维护性更加简单。 如果有效地实现了这点,就很容易地了解一部分…...

    2024/4/19 15:27:53
  4. js实现EasyUI-datagrid前台分页

    牛腩新闻发布系统中讲到过两种分页的方式:真分页与假分页这两种分页方式是怎么回事呢?所谓真分页就是从数据库中查询出需要展示的条数,比如10条,下次我再要展示25条的时候它再次访问数据库,查询前25条过来。这样有什么好处呢?减少了数据的传输量提高了第一次查询的速度。…...

    2024/4/9 11:14:29
  5. 第四十一天:又到周末了,复习一下上周做的js

    全选框的总结: ------布局方面: 1.一个大的 body标记选择器,全局进行文字大小的设置2.类选择器,定义一个类选择器,利用div划分一个区域,类选择器定义这个区域的大小和边框,margin,padding属性可以利用border的属性进行外边框的美化,这里用到的属性包括: border里面的…...

    2024/4/9 11:14:29
  6. 将整数nSum拆分成num个数的和的形式——阿里巴巴笔试题

    将一个整数nSum分解成num个整数和的形式,如nSum=6,num=3那么,nSum就可以分解成为11 4;1 2 3;222。请编程实现!方法解析:采用递归的算法,分解时,层次(nDepth,基于0)每深一层,其层所对应的值就应该不比上一层的值小,所以循环体中变量i应从上一层的值开始,直到nSum…...

    2024/4/12 16:24:07
  7. Oracle 实现分页查询

    当数据量太大,例如咱们数据库的一个表里,符合查询条件的有几十万条数据,如果你一次性查询出来的话,不仅查询速度很慢,响应时间太长影响用户体验,而且用户也看不了这么多数据。 可能有人会说可以在后台进行分页类封装处理(逻辑分页),那你首先要把查询到的几十万条数据存…...

    2024/4/9 11:14:27
  8. JavaScript设计模式--迭代器模式

    迭代器模式是指提供一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示。 JavaScript中的Array.prototype.forEach一、jQuery中的迭代器$.each([1, 2, 3], function(i, n) {console.log("当前下标为:"+ i + " 当前元素为:"+ n …...

    2024/4/12 16:23:52
  9. 人生感悟之一次面试引发的感悟

    本人是程序媛..通俗的来说就是码农。作为一个女生,当了程序媛,走上了一条不归路。以前总听到有人说,女生做IT这行会受到很多照顾。其实并不然,我并没有觉得自己受到什么特殊的待遇。都是靠技术吃饭的。谁强谁就能在若干人中脱颖而出。我是一名在京奋斗者,刚到北京的时候,…...

    2024/4/12 16:23:57
  10. STL源码剖析之序列式容器

    最近由于找工作需要,准备深入学习一下STL源码,我看的是侯捷所著的《STL源码剖析》。之所以看这本书主要是由于我过去曾经接触过一些台湾人,我一直觉得台湾人非常不错(这里不涉及任何政治,仅限个人感受),在技术上他们比较严谨,在为人处世上也非常谦虚,所以一些台湾的技…...

    2024/4/12 16:25:03
  11. IDEA使用以及常用快捷键

    目前使用到的快捷键 alt + 回车 自动补全变量名、导包、显示所有的抽象方法 alt + insert 创建构造方法、getter/setter方法 ctrl + 左键 查看源码 shift + F6 换大写double v = new Random().nextDouble(); //范围是[0,1)注意:我安装的IDEA是现在官网最新的 是自带JDK的,之前…...

    2024/4/9 11:14:23
  12. 一道关于java线程中断的题目,求大神指导,昨晚的阿里巴巴笔试题

    以下每个线程输出的结果是什么?不用关心顺序,只需输出结果集即可。public class TestThread {public static void main(String[] args){// test1Thread t1 = new Thread(){public void run(){try {int i = 0;while(i++<100000000){}System.out.println("A1");} …...

    2024/4/12 16:24:43
  13. 13.组合查询--SQL

    利用UNION操作符将多条SELECT语句组合成一个结果集。 主要有两种情况需要使用组合查询: 在一个查询中从不同的表返回结构数据; 对一个表执行多个查询,按一个查询返回数据。 UNION规则 UNION必须由两条或两条以上的SELECT语句组成,语句之间用关键字UNION分隔(因此,如果组合…...

    2024/4/12 16:24:53
  14. ElasticSearch分页查询四种解决方案与原理

    当你拼命想完成一件事的时候,你就不再是别人的对手,或者说得更确切一些,别人就不再是你的对手了,不管是谁,只要下了这个决心,他就会立刻觉得增添了无穷的力量,而他的视野也随之开阔了。——《基督山伯爵》1、from + size 浅分页 常用的分页查询根据from+size语句如下: …...

    2024/4/12 16:24:58
  15. 《STL源码剖析》笔记-stack、queue

    上一篇:《STL源码剖析》笔记-deque stack stack是一种先进后出的数据结构,它只有一个出口,只能够在顶端新增、移除、取得元素,没有其他方式进行操作。并且stack默认示意deque作为基础容器来实现的,因为vector在扩容的时候有较差的时间复杂度,而list虽然有平稳的时间复杂度…...

    2024/4/12 16:24:48
  16. IntelliJ IDEA 安装目录的核心文件讲解

    首先,我们回顾一下前两篇关于 IntelliJ IDEA 的博文的内容:在「在 Windows 系统下安装 IntelliJ IDEA 的方法」中,我们知道了在 Windows 系统下如何下载并安装 IntelliJ IDEA 的方法; 在「首次运行 IntelliJ IDEA 示例」中,我们体验了首次运行 IntelliJ IDEA 的向导功能…...

    2024/4/12 16:24:48
  17. 2016阿里巴巴c/c++研发工程师在线笔试题(附加题)(题目写的很乱,纯属碎片)

    1. 写一个二叉树,第一个数据满足二叉搜索树性质;第二个数字满足最大堆性质,且数字不一样。(图是自己构造的)结构:struct pair_t {int a;int b; }; struct node_t {int a,b;node_t *left,*right; }1) 写一个构建这个性质的二叉树的函数(传入进去俩个数组)node_t* build( p…...

    2024/4/12 16:24:58
  18. 乱舞之双刀--mhp2怪物猎人双刀攻略…

    [size=7][color=red]乱舞之双刀--mhp2怪物猎人双刀攻略~~[/color][/size] [size=12px][size=4][color=red]双刀[/color][/size] [size=4]心得:[/size] [size=3]双刀是有钱人的最好武器不过由于不能防御,取而代之的是增大攻击力及防御力的鬼人化特技,不过该特技是需要消耗体力…...

    2024/4/12 16:25:08
  19. JS设计模式之命令模式

    介绍命令模式(Command):用于将一个请求封装成一个对象,从而使你可用不同的请求对客户进行参数化,对请求排队或者记录请求日志,以及执行可撤销的操作。 即该模式旨在将函数的调用、请求和操作封装成一个单一的对象,然后对这个对象进行一系列的处理。此外,还可以通过调用实…...

    2024/4/12 16:25:03
  20. dataTable实现服务器端分页(python)

    dataTable有两种分页方式: 一种是页面分页(把数据一次性加载到页面,然后再分页),另一种是服务器端分页. 由于后台数据较多,采用页面分页耗时太长,页面分页还有一个弊端,就是除了第一页,后面的页面中的button都不能用,点击这些button没响应,要重新加载一下页面,button才…...

    2024/4/20 4:57:26

最新文章

  1. P1106 删数问题

    本题为洛谷&#xff1a; #include<iostream> #include<string> using namespace std; int main(){string n;int k;cin>>n>>k;while(k--){for(int i0;i<n.length();i){if(n[i]>n[i1]){n.erase(i,1); break;} }for(int i0;i<n.length()-1&&…...

    2024/4/24 7:51:50
  2. 梯度消失和梯度爆炸的一些处理方法

    在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言&#xff0c;在此感激不尽。 权重和梯度的更新公式如下&#xff1a; w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...

    2024/3/20 10:50:27
  3. matlab 轨迹生成函数

    文章目录 jtrajctrajmstrajmtrajtpolylspbtrinterp用例参考链接jtraj 计算两个构型之间的关节空间轨迹 [q, qd, qdd] = jtraj(q0, qf, m)是关节空间轨迹q(MxN),其中关节坐标从q0(1xN)变化到qf(1xN)。使用五次(5阶)多项式,并默认速度和加速度为零边界条件。假设时间以m步从0…...

    2024/4/21 9:36:16
  4. 第十二届蓝桥杯省赛真题(C/C++大学B组)

    目录 #A 空间 #B 卡片 #C 直线 #D 货物摆放 #E 路径 #F 时间显示 #G 砝码称重 #H 杨辉三角形 #I 双向排序 #J 括号序列 #A 空间 #include <bits/stdc.h> using namespace std;int main() {cout<<256 * 1024 * 1024 / 4<<endl;return 0; } #B 卡片…...

    2024/4/24 5:56:42
  5. [C++/Linux] UDP编程

    一. UDP函数 UDP&#xff08;用户数据报协议&#xff0c;User Datagram Protocol&#xff09;是一种无连接的网络协议&#xff0c;用于在互联网上交换数据。它允许应用程序发送数据报给另一端的应用程序&#xff0c;但不保证数据报能成功到达&#xff0c;也就是说&#xff0c;它…...

    2024/4/23 6:13:18
  6. 【外汇早评】美通胀数据走低,美元调整

    原标题:【外汇早评】美通胀数据走低,美元调整昨日美国方面公布了新一期的核心PCE物价指数数据,同比增长1.6%,低于前值和预期值的1.7%,距离美联储的通胀目标2%继续走低,通胀压力较低,且此前美国一季度GDP初值中的消费部分下滑明显,因此市场对美联储后续更可能降息的政策…...

    2024/4/23 20:58:27
  7. 【原油贵金属周评】原油多头拥挤,价格调整

    原标题:【原油贵金属周评】原油多头拥挤,价格调整本周国际劳动节,我们喜迎四天假期,但是整个金融市场确实流动性充沛,大事频发,各个商品波动剧烈。美国方面,在本周四凌晨公布5月份的利率决议和新闻发布会,维持联邦基金利率在2.25%-2.50%不变,符合市场预期。同时美联储…...

    2024/4/23 13:30:22
  8. 【外汇周评】靓丽非农不及疲软通胀影响

    原标题:【外汇周评】靓丽非农不及疲软通胀影响在刚结束的周五,美国方面公布了新一期的非农就业数据,大幅好于前值和预期,新增就业重新回到20万以上。具体数据: 美国4月非农就业人口变动 26.3万人,预期 19万人,前值 19.6万人。 美国4月失业率 3.6%,预期 3.8%,前值 3…...

    2024/4/23 13:28:06
  9. 【原油贵金属早评】库存继续增加,油价收跌

    原标题:【原油贵金属早评】库存继续增加,油价收跌周三清晨公布美国当周API原油库存数据,上周原油库存增加281万桶至4.692亿桶,增幅超过预期的74.4万桶。且有消息人士称,沙特阿美据悉将于6月向亚洲炼油厂额外出售更多原油,印度炼油商预计将每日获得至多20万桶的额外原油供…...

    2024/4/20 23:26:47
  10. 【外汇早评】日本央行会议纪要不改日元强势

    原标题:【外汇早评】日本央行会议纪要不改日元强势近两日日元大幅走强与近期市场风险情绪上升,避险资金回流日元有关,也与前一段时间的美日贸易谈判给日本缓冲期,日本方面对汇率问题也避免继续贬值有关。虽然今日早间日本央行公布的利率会议纪要仍然是支持宽松政策,但这符…...

    2024/4/23 13:27:44
  11. 【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响

    原标题:【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响近日伊朗局势升温,导致市场担忧影响原油供给,油价试图反弹。此时OPEC表态稳定市场。据消息人士透露,沙特6月石油出口料将低于700万桶/日,沙特已经收到石油消费国提出的6月份扩大出口的“适度要求”,沙特将满…...

    2024/4/19 11:57:53
  12. 【外汇早评】美欲与伊朗重谈协议

    原标题:【外汇早评】美欲与伊朗重谈协议美国对伊朗的制裁遭到伊朗的抗议,昨日伊朗方面提出将部分退出伊核协议。而此行为又遭到欧洲方面对伊朗的谴责和警告,伊朗外长昨日回应称,欧洲国家履行它们的义务,伊核协议就能保证存续。据传闻伊朗的导弹已经对准了以色列和美国的航…...

    2024/4/23 13:29:53
  13. 【原油贵金属早评】波动率飙升,市场情绪动荡

    原标题:【原油贵金属早评】波动率飙升,市场情绪动荡因中美贸易谈判不安情绪影响,金融市场各资产品种出现明显的波动。随着美国与中方开启第十一轮谈判之际,美国按照既定计划向中国2000亿商品征收25%的关税,市场情绪有所平复,已经开始接受这一事实。虽然波动率-恐慌指数VI…...

    2024/4/23 13:27:22
  14. 【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试

    原标题:【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试美国和伊朗的局势继续升温,市场风险情绪上升,避险黄金有向上突破阻力的迹象。原油方面稍显平稳,近期美国和OPEC加大供给及市场需求回落的影响,伊朗局势并未推升油价走强。近期中美贸易谈判摩擦再度升级,美国对中…...

    2024/4/23 13:28:42
  15. 【原油贵金属早评】市场情绪继续恶化,黄金上破

    原标题:【原油贵金属早评】市场情绪继续恶化,黄金上破周初中国针对于美国加征关税的进行的反制措施引发市场情绪的大幅波动,人民币汇率出现大幅的贬值动能,金融市场受到非常明显的冲击。尤其是波动率起来之后,对于股市的表现尤其不安。隔夜美国股市出现明显的下行走势,这…...

    2024/4/23 22:01:21
  16. 【外汇早评】美伊僵持,风险情绪继续升温

    原标题:【外汇早评】美伊僵持,风险情绪继续升温昨日沙特两艘油轮再次发生爆炸事件,导致波斯湾局势进一步恶化,市场担忧美伊可能会出现摩擦生火,避险品种获得支撑,黄金和日元大幅走强。美指受中美贸易问题影响而在低位震荡。继5月12日,四艘商船在阿联酋领海附近的阿曼湾、…...

    2024/4/23 13:29:23
  17. 【原油贵金属早评】贸易冲突导致需求低迷,油价弱势

    原标题:【原油贵金属早评】贸易冲突导致需求低迷,油价弱势近日虽然伊朗局势升温,中东地区几起油船被袭击事件影响,但油价并未走高,而是出于调整结构中。由于市场预期局势失控的可能性较低,而中美贸易问题导致的全球经济衰退风险更大,需求会持续低迷,因此油价调整压力较…...

    2024/4/23 13:27:46
  18. 氧生福地 玩美北湖(上)——为时光守候两千年

    原标题:氧生福地 玩美北湖(上)——为时光守候两千年一次说走就走的旅行,只有一张高铁票的距离~ 所以,湖南郴州,我来了~ 从广州南站出发,一个半小时就到达郴州西站了。在动车上,同时改票的南风兄和我居然被分到了一个车厢,所以一路非常愉快地聊了过来。 挺好,最起…...

    2024/4/23 13:47:22
  19. 氧生福地 玩美北湖(中)——永春梯田里的美与鲜

    原标题:氧生福地 玩美北湖(中)——永春梯田里的美与鲜一觉醒来,因为大家太爱“美”照,在柳毅山庄去寻找龙女而错过了早餐时间。近十点,向导坏坏还是带着饥肠辘辘的我们去吃郴州最富有盛名的“鱼头粉”。说这是“十二分推荐”,到郴州必吃的美食之一。 哇塞!那个味美香甜…...

    2024/4/19 11:59:23
  20. 氧生福地 玩美北湖(下)——奔跑吧骚年!

    原标题:氧生福地 玩美北湖(下)——奔跑吧骚年!让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 啊……啊……啊 两…...

    2024/4/19 11:59:44
  21. 扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!

    原标题:扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!扒开伪装医用面膜,翻六倍价格宰客!当行业里的某一品项火爆了,就会有很多商家蹭热度,装逼忽悠,最近火爆朋友圈的医用面膜,被沾上了污点,到底怎么回事呢? “比普通面膜安全、效果好!痘痘、痘印、敏感肌都能用…...

    2024/4/23 13:28:08
  22. 「发现」铁皮石斛仙草之神奇功效用于医用面膜

    原标题:「发现」铁皮石斛仙草之神奇功效用于医用面膜丽彦妆铁皮石斛医用面膜|石斛多糖无菌修护补水贴19大优势: 1、铁皮石斛:自唐宋以来,一直被列为皇室贡品,铁皮石斛生于海拔1600米的悬崖峭壁之上,繁殖力差,产量极低,所以古代仅供皇室、贵族享用 2、铁皮石斛自古民间…...

    2024/4/23 13:29:47
  23. 丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者

    原标题:丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者【公司简介】 广州华彬企业隶属香港华彬集团有限公司,专注美业21年,其旗下品牌: 「圣茵美」私密荷尔蒙抗衰,产后修复 「圣仪轩」私密荷尔蒙抗衰,产后修复 「花茵莳」私密荷尔蒙抗衰,产后修复 「丽彦妆」专注医学护…...

    2024/4/23 13:28:14
  24. 广州械字号面膜生产厂家OEM/ODM4项须知!

    原标题:广州械字号面膜生产厂家OEM/ODM4项须知!广州械字号面膜生产厂家OEM/ODM流程及注意事项解读: 械字号医用面膜,其实在我国并没有严格的定义,通常我们说的医美面膜指的应该是一种「医用敷料」,也就是说,医用面膜其实算作「医疗器械」的一种,又称「医用冷敷贴」。 …...

    2024/4/23 13:27:51
  25. 械字号医用眼膜缓解用眼过度到底有无作用?

    原标题:械字号医用眼膜缓解用眼过度到底有无作用?医用眼膜/械字号眼膜/医用冷敷眼贴 凝胶层为亲水高分子材料,含70%以上的水分。体表皮肤温度传导到本产品的凝胶层,热量被凝胶内水分子吸收,通过水分的蒸发带走大量的热量,可迅速地降低体表皮肤局部温度,减轻局部皮肤的灼…...

    2024/4/23 13:27:19
  26. 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...

    解析如下&#xff1a;1、长按电脑电源键直至关机&#xff0c;然后再按一次电源健重启电脑&#xff0c;按F8健进入安全模式2、安全模式下进入Windows系统桌面后&#xff0c;按住“winR”打开运行窗口&#xff0c;输入“services.msc”打开服务设置3、在服务界面&#xff0c;选中…...

    2022/11/19 21:17:18
  27. 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。

    %读入6幅图像&#xff08;每一幅图像的大小是564*564&#xff09; f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...

    2022/11/19 21:17:16
  28. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...

    win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面&#xff0c;在等待界面中我们需要等待操作结束才能关机&#xff0c;虽然这比较麻烦&#xff0c;但是对系统进行配置和升级…...

    2022/11/19 21:17:15
  29. 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...

    有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows&#xff0c;请勿关闭计算机”的提示&#xff0c;要过很久才能进入系统&#xff0c;有的用户甚至几个小时也无法进入&#xff0c;下面就教大家这个问题的解决方法。第一种方法&#xff1a;我们首先在左下角的“开始…...

    2022/11/19 21:17:14
  30. win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...

    置信有很多用户都跟小编一样遇到过这样的问题&#xff0c;电脑时发现开机屏幕显现“正在配置Windows Update&#xff0c;请勿关机”(如下图所示)&#xff0c;而且还需求等大约5分钟才干进入系统。这是怎样回事呢&#xff1f;一切都是正常操作的&#xff0c;为什么开时机呈现“正…...

    2022/11/19 21:17:13
  31. 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...

    Win7系统开机启动时总是出现“配置Windows请勿关机”的提示&#xff0c;没过几秒后电脑自动重启&#xff0c;每次开机都这样无法进入系统&#xff0c;此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一&#xff1a;开机按下F8&#xff0c;在出现的Windows高级启动选…...

    2022/11/19 21:17:12
  32. 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...

    有不少windows10系统用户反映说碰到这样一个情况&#xff0c;就是电脑提示正在准备windows请勿关闭计算机&#xff0c;碰到这样的问题该怎么解决呢&#xff0c;现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法&#xff1a;1、2、依次…...

    2022/11/19 21:17:11
  33. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...

    今天和大家分享一下win7系统重装了Win7旗舰版系统后&#xff0c;每次关机的时候桌面上都会显示一个“配置Windows Update的界面&#xff0c;提示请勿关闭计算机”&#xff0c;每次停留好几分钟才能正常关机&#xff0c;导致什么情况引起的呢&#xff1f;出现配置Windows Update…...

    2022/11/19 21:17:10
  34. 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...

    只能是等着&#xff0c;别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚&#xff0c;只能是考虑备份数据后重装系统了。解决来方案一&#xff1a;管理员运行cmd&#xff1a;net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...

    2022/11/19 21:17:09
  35. 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?

    原标题&#xff1a;电脑提示“配置Windows Update请勿关闭计算机”怎么办&#xff1f;win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢&#xff1f;一般的方…...

    2022/11/19 21:17:08
  36. 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...

    关机提示 windows7 正在配置windows 请勿关闭计算机 &#xff0c;然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;关机提示 windows7 正在配…...

    2022/11/19 21:17:05
  37. 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...

    钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...

    2022/11/19 21:17:05
  38. 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...

    前几天班里有位学生电脑(windows 7系统)出问题了&#xff0c;具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面&#xff0c;长时间没反应&#xff0c;无法进入系统。这个问题原来帮其他同学也解决过&#xff0c;网上搜了不少资料&#x…...

    2022/11/19 21:17:04
  39. 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...

    本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法&#xff0c;并在最后教给你1种保护系统安全的好方法&#xff0c;一起来看看&#xff01;电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中&#xff0c;添加了1个新功能在“磁…...

    2022/11/19 21:17:03
  40. 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...

    许多用户在长期不使用电脑的时候&#xff0c;开启电脑发现电脑显示&#xff1a;配置windows更新失败&#xff0c;正在还原更改&#xff0c;请勿关闭计算机。。.这要怎么办呢&#xff1f;下面小编就带着大家一起看看吧&#xff01;如果能够正常进入系统&#xff0c;建议您暂时移…...

    2022/11/19 21:17:02
  41. 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...

    配置windows update失败 还原更改 请勿关闭计算机&#xff0c;电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;配置windows update失败 还原更改 请勿关闭计算机&#x…...

    2022/11/19 21:17:01
  42. 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...

    不知道大家有没有遇到过这样的一个问题&#xff0c;就是我们的win7系统在关机的时候&#xff0c;总是喜欢显示“准备配置windows&#xff0c;请勿关机”这样的一个页面&#xff0c;没有什么大碍&#xff0c;但是如果一直等着的话就要两个小时甚至更久都关不了机&#xff0c;非常…...

    2022/11/19 21:17:00
  43. 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...

    当电脑出现正在准备配置windows请勿关闭计算机时&#xff0c;一般是您正对windows进行升级&#xff0c;但是这个要是长时间没有反应&#xff0c;我们不能再傻等下去了。可能是电脑出了别的问题了&#xff0c;来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...

    2022/11/19 21:16:59
  44. 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...

    我们使用电脑的过程中有时会遇到这种情况&#xff0c;当我们打开电脑之后&#xff0c;发现一直停留在一个界面&#xff1a;“配置Windows Update失败&#xff0c;还原更改请勿关闭计算机”&#xff0c;等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢&#xff0…...

    2022/11/19 21:16:58
  45. 如何在iPhone上关闭“请勿打扰”

    Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...

    2022/11/19 21:16:57