STL源码分析之一 : 迭代器详解

深度学习:RBM理论与C++实战 深度学习:RBM理论与C++实战深度学习:RBM理论与C++实战 阅读详情

Author : cppgp
Time : 2007-09-26

本系列文章将会尽可能的剖析STL实现细节。本文假定读者对象是热爱GP编程、希望探究STL实现的程序员。本系列不适合STL初学者。

[本篇分析STL迭代器,在文章最后给出一个拥有迭代器和常用操作的仿STL实现的单链表源码]

1.概述
 《Design Patterns》中iterator模式的定义如下:提供一种方法,使之能够依序寻访某个聚合物(容器)所含的各个元素。
 在STL中,迭代器是一种行为类似指针的对象,可透过与一般指针一致的接口来完成自己的工作(事实上除了随机迭代器以外,其他迭代器只有比指针更少的操作,但是所有迭代器都有提领操作(*iterator)、成员访问操作(iterator->member)、前置递增操作(++iterator)、后置递增操作(iterator++),是容器和算法的粘合剂。同时透过迭代器,向操作者隐藏了具体数据结构和实现细节。例如,我们要遍历某个容器,可以不必关心其采用的数据结构是数组、链表或者某种图结构,只需要定义一个迭代器,然后按照如下操作:
  for( iterator iter = container.begin() ;  container.end() != iter ; ++iter )
   <process>(*iter);
 其中container是任意容器。<process>是准备遍历施加的操作。
 按照迭代器可以施行的操作将其分为5种,分别是
  (1)输入迭代器(input iterator);
  (2)输出迭代器(output iterator);
  (3)前向迭代器(forward iterator);
  (4)双向迭代器(bidirectional iterator);
  (5)随机迭代器(random access iterator)。
 当不同的迭代器作为参数传递给对应算法时,算法会根据迭代器特性提供最大优化。例如,STL中的distance()对于不同的迭代器,算法不同,分别如下:
 template <class _InputIterator, class _Distance>
 inline void __distance
 (_InputIterator __first,
  _InputIterator __last,
  _Distance& __n,
  input_iterator_tag)
 {
  while (__first != __last) { ++__first; ++__n; }
 }

 template <class _RandomAccessIterator, class _Distance>
 inline void __distance
 (_RandomAccessIterator __first,
  _RandomAccessIterator __last,
  _Distance& __n,
  random_access_iterator_tag)
 {
  __n += __last - __first;
 }
 template <class _InputIterator, class _Distance>
 inline void distance
 (_InputIterator __first,
  _InputIterator __last,
  _Distance& __n)
 {
  __distance(__first, __last, __n, iterator_category(__first));
 }

2.STL中迭代器层次关系
struct output_iterator_tag{}
struct input_iterator_tag{}
struct forward_iterator_tag : public input_iterator_tag {};
struct bidirectional_iterator_tag : public forward_iterator_tag{}
struct random_accessl_iterator_tag : public bidirectional_iterator_tag{}

3.使用
 OutIt:只能通过存储来间接地拥有一个值V。在输出迭代器中存储一个值后必须将其递增。例如:
  *X++ = V; *X = V,++X; *X = V,X++;
 InIt:如果其值不为end-of-sequence,可以间接的存取它所拥有的值。例如:
  V = *X; V = *X++;
  一旦对其递增,其所有其他拷贝不保证能完成比较、取值、递增等操作。
 FwdIt:假设X是FwdIt,如果*X可变,就可替换InIt。可以同时拥有一个前向迭代器的多份拷贝,它们中的每一份都可以各自间接取值,或者各自进行递增。
 BidIt:可以用它来替换FwdIt,同时可以进行诸如--X和X--相关的递减操作。
 RanIt:除了有BidIt相关操作之外,可以进行任何指针算术运算。

*********************************************************
  五类迭代器的详述
*********************************************************
1.输出迭代器(output iterator)
1).struct output_iterator_tag{}
 用来读取有序序列中的元素。既可用来表示将值存储到对象中,也可表示从一个对象中获得它所保存的值。如果需要创建一个新的值序列并且以有序的方式来产生值,可用如下循环语句:
 for( ; <not done> ; ++next )
  *next = <whatever>;
 或者:
 while( <not done> )
 {
  *next++ = <whatever>;
 }
 其中,next表示一个迭代器类型为X的对象;<not done>是一个检测循环是否应该终止的谓词(predicate);<whatever>是一个表达式,类型为序列中元素的类型T或者可以转化为T的类型。

2).所拥有的操作:
 a).提领操作 (*a,作为左值才有效)
 b).前置递增操作 (++a)
 c).后置递增操作 (a++)
 d).复制构造函数(copy constructor)
 e).析构函数(destructor)
 f).赋值操作符(assignment operator)

3).限制条件
 必须保证输出迭代器在存储每一个元素后得以增加;
 必须保证输出迭代器在两次存储的间隔内增加的次数不得超过一次;
 输入迭代器只在类似 1) 中给出的循环语句中使用。

4).操作说明:
 对于输出迭代器,只可以向目的序列一个一个的写入,只能一个一个地赋新值,而且不能对同一序列进行两次遍历。如果在相同位置上进行第二次写入,不能确保这次写入的值会3覆盖前一次写入的值。operator*只有作为左值才有效。Output Iterator无须比较(comparison)操作,无法判断迭代器是否有效,或写入是否成功。使用者唯一可做的就是写入写入再写入。纯粹Output Iterator的一个典型例子就是“将元素写至标准输出装置”,另一个就是Inserters,以后详述。其所有操作如下:
  *iter = value;  //将数值写入迭代器所指位置
  ++iter;   //向前步进(传回新位置)
  iter++;   //向前步进(传回旧位置)
  TYPE(iter)  //复制迭代器(copy构造函数)

5).特性说明
[参数说明]X:迭代器类型,a的类型为X&,T是元素类型,t的类型是T

表达式  结果的类型  含义   注释

X(a)  X   产生a的一个拷贝  析构函数是可见的
        *X(a)=t与*a=t的作用相同
X u(a)  X&   u是a的一个拷贝  
X u=a

r=a  X&   a赋值给r  结果*r=t和*a=t作用相同

*a=t  void   在序列中存储新元素 

++r  X&   指向下一个元素  &r = &++r,r不是end-of-sequence

r++  const X&  指向下一个元素  &r = &r++
     {X temp = *r; ++r; return temp;}
*r++=t  void

 

2.输入迭代器(input interator)

1).struct input_iterator_tag{}
用来产生新的序列,可顺序存取已有值或对已有序列进行排序。可用于如下循环语句:
 for( p = first ; p != last ; ++p )
 {
  <process>(*)p
 }
 其中p、first、last都是迭代器类型X的对象,<process>是一个能接受T类型为参数的函数
2).所拥有的操作:
 a).提领操作 (*a)
 b).成员访问操作 (a->member)
 c).前置递增操作 (++a)
 d).后置递增操作 (a++)
 e).复制构造函数(copy constructor)
 f).析构函数(destructor)
 g).赋值操作符(assignment operator)

3).限制条件
 两个迭代器中只有一个具有end-of-sequence值时输入迭代器之间的比较才一定有意义
 输入迭代器只在类似 1) 中给出的循环语句中使用。

4).操作说明:
 对于输入迭代器,只能一次一个向前读元素,按此顺序一个个传回元素值,而且只能读一次。如果复制Input Iterator,并使原Input Iterator和新产生的Input Iterator都向前读取,可能会遍历到不同值。纯粹Input Iterator的一个典型例子就是从“标准输入装置读取数据”的迭代器(比如从键盘)。两个Input Iterator占用同一个位置则其相等,但是其传回值不一定相等。其所有操作如下:
   *iter;   //读取实际元素,提领操作
   iter->member;  //读取实际元素的成员(果T是结构化类型),成员访问操作
   ++iter;   //向前步进(传回新位置),前置递增操作
   iter++;   //向前步进(传回旧位置),后置递增操作
   iter1 = iter2;  //赋值操作
   iter1 == iter2;  //判断两个迭代器是否相等,a和b在同一值域内
   iter1 != iter2;  //判断两个迭代器是否不等,a和b在同一值域内
   TYPE(iter)  //复制迭代器(copy构造函数)

  说明:应该尽量使用前置式递增

5).特性说明
[参数说明]X:迭代器类型,a的类型为X&,T是元素类型,t的类型是T,m是T的成员,m的类型是M

表达式  结果的类型  含义   注释

X(a)  X   产生a的一个拷贝  析构函数是可见的
        *X(a)与*a的作用相同
X u(a)  X&   u是a的一个拷贝  创建完成后u等于a
X u=a

r=a  X&   a赋值给r  结果r=a

a == b  bool   相等比较  a和b在同一值域内

a != b  bool   !(a==b)   同上

*a  T   从序列中取元素  a不是end-of-sequence

a->m  M   (*a).m   T的成员m

++r  X&   指向下一个元素  &r = &++r

r++  void   指向下一个元素  &r = &r++
     {X temp = *r; ++r; return temp;}

3.前向迭代器(forward iterator)
1).struct forward_iterator_tag{}
 可以比较两个前向迭代器是否相等,同时他们可以都为或都不为end-of-sequence,但是如前,这两个迭代器必须处于同一个值域。同时可以用一个前向迭代器的多个有效拷贝值来指向当前序列中的任意位置。前向迭代器不能回退,不能直接(随机)存取任意元素。可以简单想象它为一个单向链表中元素的指针。

2).所拥有的操作:
 a).提领操作
 b).成员操作
 c).前置递增操作 (++a)
 d).后置递增操作 (a++)
 e).默认构造函数
 d).复制构造函数(copy constructor)
 e).析构函数(destructor)
 f).赋值操作符(assignment operator)


3).操作说明:
 Forward Iterator 是 Output Iterator 和 Input Iterator的结合,具有 Input Iterator 的全部功能和 Output Iterator的大部分功能,事实上在STL中,forward iterator 派生自 input iterator。其所有操作如下:
   *iter;   //存取实际元素
   iter->member;  //存取实际元素的成员,如果有的话
   ++iter;   //向前步进(传回新位置)
   iter++;   //向前步进(传回旧位置)
   iter1 == iter2;  //判断两个迭代器是否相等
   iter1 != iter2;  //判断两个迭代器是否不等
   TYPE();   //产生迭代器(default构造函数)
   TYPE(iter);  //复制迭代器(copy构造函数)
   iter1 = iter2;  //赋值

 Forward Iterator有Output Iterator的大部分功能而非全部功能的原因是某些对Output Iterator有效的程序对Forward Iterator可能无效。有以下两点:
 (1)面对Output Iterator无须检查其是否抵达序列尾端,便可直接写入数据。事实上由于Output Iterator不提供比较操作,因此无法将Output Iterator与end-of-sequence相比较。以下循环是正确的:
   while(true)
   {
    *pos = foo();
    ++pos;
   }

 (2)对于Forward Iterator,必须在提领数据之前确保其有效,因此上述循环对Forward Iterator是错误的。对于Forward Iterator上述循环应改为:
    while( pos != coll.end() )
   {
    *pos = foo();
    ++pos;
   }
 而同时,该循环不适用于Output Iterator,因为Output Iterator没有operator!=


4).特性说明
[参数说明]注释:X是迭代器类型,a和b的类型为X;r和s的类型为X&;T是元素类型,t的类型为T,m是T的成员,m的类型是M。


表达式  结果的类型  含义   注释
X()  X   产生一个默认值  析构函数是可见的,值可以是end-of-sequence

X u  X&   u具有默认值  创建完成后 u == a
X u =a

X(a)  X   产生a的一个拷贝  析构函数是可见的,*X(a)与*a的作用相同

X u(a)  X&   u是a的一个拷贝  创建完成后 u == a
X u =a

r = a  X&   a赋值给r  结果 r == a

a == b  bool   相等比较  a和b在同一值域内
a != b  bool   !( a == b )  

*a  T&   从序列中存取元素 a不是end-of-sequence,a == b <==> *a == *b
 
*a = t  T&   在元素中存储  a不是end-of-sequence,a是可变的

a -> m  M   (*a).m   T有成员m

++r  X&   指向下一个元素  &r = &++r,r不是end-of-sequence,r == s <==> ++r == ++s

r++  const X&  {X tmp(r);++r;return tmp;}  
*r++  void   {T tmp = *r;++r;return tmp;}


4.双向迭代器(bidirectional iterator)
1).struct bidirectional_iterator_tag{}
 具有前向迭代器的所有特性,另外还具有逆向移动特性。可以简单想象它为一个双向链表中元素的指针。

2).所拥有的操作:
 a).前向迭代器的所有操作
 b).前置递减操作 (--a)
 c).后置递减操作 (a--)

3).操作说明:
 Forward Iterator的所有操作均可用,新增加的操作如下:
   --iter;   //只向前一个元素,传回新位置
   iter--;   //只向前一个元素,传回旧位置

4).特性说明
[参数说明]注释:X是迭代器类型,a和b的类型为X;r和s的类型为X&;T是元素类型,t的类型为T,m是T的成员,m的类型是M。
有Forward Iterator的所有特性,新加特性如下:

表达式  结果的类型  含义   注释
--r  X&   指向前一个元素  &r = &--r,r不是end-of-sequence,r == s <==> --r == --s
r--  const X&  {X tmp(r);++r;return tmp;}  
*r++  void   {T tmp = *r;++r;return tmp;}


5.随机迭代器(random access iterator)
1).struct random_access_iterator_tag{}
 具有双向迭代器的所有特性,另外还具有支持加减、大小判断、迭代器在序列中的顺序、下标操作迭代器特性。可以简单想象它为一个数组中元素的指针。

2).所拥有的操作:
 a).双向迭代器的所有操作
 b).加减操作(a+=n;a-=n;a+n;a-n;a-b;b-a)
 c).大小判断(a>b;a<b;a>=b;a<=b)
 d).下标操作(a[n])

3).操作说明:
 Bidirectional Iterator的所有操作均可用,新增加的操作如下:
   iter1 < iter2;
   iter1 <= iter2;
   iter += n;
   iter -= n;
   iter + n;
   n + iter;
   iter - n;
   n - iter;
   iter1 - iter2;
   iter[n]

4).特性说明
[参数说明]注释:X是迭代器类型,a和b的类型为X;r和s的类型为X&;T是元素类型,t的类型为T;Dist是X的差距类型
有Forward Iterator的所有特性,新加特性如下:

表达式  结果的类型  含义   注释
a < b  bool   从a可以到达b  a和b在同一值域中
a > b  bool   b < a  
a <= b  bool   !(b < a)  
a >= b  bool   !(a < b)  
r += n  X&   {Dist m = n;while(0<m)--m,++r;while(m<0)++m,--r;return r;}

a + n  X   {X tmp(a);tmp += n;return tmp;}
n + a

r -= n  X&   r += -n;  
a - n  X   a + (-n)  
b - a  Dist   {Dist m = 0;while(a<b)++a,++m;while(b<a)++b;--m;return m;}  
a[n]  T的任意类型  *(a+n)

 

#include <new>
//这个是链表基本结构,里面不存储任何东西,纯粹为了实现算法
struct SListBaseNode
{
    SListBaseNode
* s_Next;
}
;

//这个函数在prevNode节点后面插入新节点 newNode
inline SListBaseNode* InsertAfterNode( SListBaseNode* prevNode , SListBaseNode* newNode )
{
    newNode
->s_Next = prevNode->s_Next;    //newNode的下一节点为prevNode的下一节点
    prevNode->s_Next = newNode;        //prevNode的下一节点为newNode
    return newNode;                //返回newNode,实现串接算法,详细见下面的[注释1]
}


/*
    [注释1] : 这类算法返回的原因是为了实现链接调用,例如:
        InsertAfterNode( InsertAfterNode(front,newNode1) , newNode2 );
        再比如c库函数strcpy等都是这个原因,例如:
        char buff[128];
        int len = strlen( strcpy(buff,"yanyg") );
*/


//这个函数得到节点node的前一节点
inline SListBaseNode* GetPrevious( SListBaseNode* front , const SListBaseNode* node )
{
    
for ( ; front && front->s_Next != node ; front = front->s_Next );
    
return front;
}


//这个函数是前一个函数的const版本
inline const SListBaseNode* GetPrevious( const SListBaseNode* front , const SListBaseNode* node )
{
    
for ( ; front && front->s_Next != node ; front = front->s_Next );
    
return front;
}


//这个函数逆序链表,并返回最后一个节点
inline SListBaseNode* Reverse( SListBaseNode* node )
{
    SListBaseNode
* result = node;

    node 
= node->s_Next;
    result
->s_Next = 0;

    
while ( node )
    
{
        SListBaseNode
* next = node->s_Next;
        node
->s_Next = result;
        result 
= node;
        node 
= next;
    }


    
return result;
}


//计算node之后的节点个数
inline size_t ListSize( SListBaseNode* node )
{
    size_t result 
= 0;

    
for ( ; 0 != node ; node = node->s_Next , ++result );

    
return result;
}


//这个派生是链表具体存储的对象
template<typename T>
struct SListNode : 
public SListBaseNode
{
    SListNode():s_Next(
0){}
    SListNode( 
const T& t ):s_Data(t){ s_Next = 0; }
    T s_Data;
}
;

/************************************************************************
*    这里实现一个简单的迭代器
*    如果想和stl完美融合
*    那么需要从stl迭代器萃取某些特征型别信息
*    型别萃取不是本篇重点,不再详细论述
*    单链表是一个forward_iterator
*    因此只实现 iter++/++iter/*iter/iter->member/==/!=六种操作
***********************************************************************
*/

template
<class T , class Ref , class Ptr >
struct SList_Iterator
{
    typedef SList_Iterator
<T,T&,T*> iterator;
    typedef SList_Iterator
<T,const T&,const T*> const_iterator;
    typedef SList_Iterator
<T,Ref,Ptr> self;

    typedef T value_type;
    typedef Ptr pointer;
    typedef Ref reference;
    typedef SListNode
<T> list_node;

    SList_Iterator( list_node
* x ):s_Node(x){}
    SList_Iterator():s_Node(
0){}
    SList_Iterator( const_iterator
& x ):s_Node(x.s_Node){}

    reference operator
*() const { return ((list_node*)s_Node)->s_Data; }
    pointer operator
->() const { return &(operator*()); }

    self
& operator++()
    
{
        s_Node 
= s_Node->s_Next;
        
return *this;
    }


    
const self operator++(int)
    
{
        self tmp(
*this);
        s_Node 
= s_Node->s_Next;

        
return tmp;
    }


    bool operator
==( const SList_Iterator& x ){ return s_Node == x.s_Node; }
    bool operator
!=( const SList_Iterator& x ){ return s_Node != x.s_Node; }

    SListBaseNode
* s_Node;
}
;

//单链表类实现
template < class T >
class SList
{
public:
    typedef T value_type;
    typedef value_type
* pointer;
    typedef 
const value_type* const_pointer;
    typedef value_type
& reference;
    typedef 
const value_type& const_reference;
    typedef size_t size_type;
    typedef ptrdiff_t difference_type;

    typedef SList_Iterator
< T , T& , T* > iterator;
    typedef SList_Iterator
< T, const T&, const T* > const_iterator;


private:
    typedef SListNode
<T> list_node;
    typedef SListBaseNode list_node_base;

    list_node_base m_Head;

public:
    SList() 
{ m_Head.s_Next = 0; }    //初始化
    ~SList(){ clear(); }        //删除内存

    iterator begin() 
{ return iterator( (list_node*)m_Head.s_Next ); }
    iterator end() 
{ return iterator(0); }
    const_iterator begin() 
const { return const_iterator( (list_node*)m_Head.s_Next ); }
    const_iterator end() 
const { return const_iterator(0); }
    size_t size() 
const { return ListSize(m_Head.s_Next); }
    size_t max_size() 
const { return size_t(-1); }
    bool empty() 
const { return 0 == m_Head.s_Next; }

    reference front() 
{ return ((list_node*)m_Head.s_Next)->s_Data; }
    const_reference front() 
const { return ((list_node*)m_Head.s_Next)->s_Data; }

    
void push_front( const value_type& t ) { InsertAfterNode(&m_Head,new list_node(t)); }
    
void pop_front() { list_node* node = (list_node*)(m_Head.s_Next); m_Head.s_Next = node->s_Next; delete (list_node*)node; }

    iterator previous( const_iterator pos ) 
{ return iterator(GetPrevious(m_Head.s_Next,pos)); }
    const_iterator previous( const_iterator pos ) 
const { return const_iterator(GetPrevious(m_Head.s_Next,pos)); }

    iterator insert( iterator pos, 
const value_type& x ){ return iterator((list_node*)InsertAfterNode( GetPrevious(&m_Head,pos.s_Node),new list_node(x))); }
    iterator insert_after( iterator pos, 
const value_type& x ){ return iterator( (list_node*)InsertAfterNode(pos.s_Node,new list_node(x) ) ); }
    
void erase( iterator pos ){ SListBaseNode* temp = GetPrevious(&m_Head,pos.s_Node); temp->s_Next = pos.s_Node->s_Next; delete (list_node*)pos.s_Node; }
    
void erase_after( iterator pos ) { iterator tmp(pos); ++pos; tmp.s_Node->s_Next = pos.s_Node->s_Next; delete (list_node*)pos.s_Node; }

    
void reverse(){ m_Head.s_Next = Reverse(m_Head.s_Next); }

    
void clear(){ list_node_base* node=m_Head.s_Next; for(;0!=node;node=m_Head.s_Next)m_Head.s_Next=node->s_Next,delete (list_node*)node; }
}
;

 

STL源码学习系列四: 迭代器(Iterator) 迭代器(Iterator) 前言 在STL的思想中,容器和算法是彼此独立设计的,再通过某种方式使它们连接;而迭代器是使算法独立于使用的容器类型,即迭代器是连接算法和容器的方法。由于迭代器是一种行为类似指针的对象,也就说迭代器是一种广义指针,即迭代器对解除引用操作(operator*)和访问成员操作(operator-&amp;gt;)进行重载。然而要对这两个操作符进行重载,对容器内部对象的数据... 阅读详情

相关推荐

STL源码分析(总结)

STL六大组件 容器(containers):是一种class template,里面包含各种数据结构。 算法(algorithms):是一种function template,里面包含各种算法。 迭代器(iterators):是所谓的泛型指针,每个容器都有自己的专属的迭代器,知道如何遍历自己的元素。 仿函数(functors):是一种重载了operator()的class或class templa

cdcupt的博客 5118

STL迭代器

迭代器(iterator)是连接容器和算法的纽带,为数据提供了抽象,使写算法的人不必关心各种数据结构的细节。迭代器提供了数据访问的标准模型——对象序列,使对容器更广泛的访问操作成为可能。 泛型编程的关键所在,就是如何找到一种通用的方法,来访问具有不同结构的各种容器中的每个元素,而这正是迭代器的功能。 迭代器是一种广义的指针,是指向序列元素指针概念的一种抽象。迭代器可以指向容器中的任意元素,还能

ouyangfuchao的专栏 689

STL中的sort源码分析

title: STL中的sort源码分析 date: 2020-12-08 20:43:11 tags: STL | source code categories: C++ | STL 前言 本文采用gcc5.4.0版本的STL进行分析,链接:在线源码。在下文的分析中都具体指出了对应文件的多少行,方便读者对照查看。如你想要在自己电脑上查看源码,相信你已经安装了gcc,STL绝大多数源码都位于/usr/include/c++/10.2.0/bits目录下。 我们都听说sort()内部是使用快速排序,但是实际.

qq_51604252的博客 1084

STL源码剖析:迭代器的概念理解,以及代码测试。

目的:理解STL源码 迭代器的缘由来自于一种设计模式。它提供一个方法,让用户能够一一的访问里面的数据,而不用管里面的数据的组成的结构(树状,线性,数组,图等结构)。它不同于数据结构的访问样子,它统一的一一访问完整的数据。 在STL中迭代器不但能够一一访问里面的数据,它同时可以作为一个粘合剂,将数据结构和算法分开。数据结构和算法分来,不但能够易于阅读和写代码,同时符合开发中的开闭原则。如果每个数据结构用一个算法,算法可以在别处开发,然后用迭代器把数据结构和算法粘合在一起。具体测试如下:数据结构有vector,

weixin_43851636的博客 871

GEE进行Theil-Sen Median斜率估计和Mann-Kendall检验

Python实现Theil-Sen Median斜率估计和Mann-Kendall检验// 定义时间范围//NDVI图像集合// 定义每年的开始和结束日期// 加载NDVI数据集,按日期过滤,并计算最大值.max()}));// 计算Sen斜率并剪裁// 可视化Sen斜率Map.addLayer(senSlope.select('slope'), vis, "Sen斜率 ");// MK检验// 创建一个列表,包含年度NDVI图像的list。

qq_44894692的博客 965

APM 飞行模式切换--源码详解

APM飞控中有很多种方式可以改变飞行模式。其中最常见的为遥控器切换和地面站切换两种方式。 下面以遥控器切换为例详解飞行模式切换逻辑。 APM遥控器切换飞行模式的源代码在RC_Channel.cpp文件中的RC_Channel_Copter::do_aux_function_change_mode()函数中。 const bool success = copter.set_mode()调用Copter::set_mode()函数,在set_mode()函数中调用mode_fro...

qq_30623591的博客 2440

STL学习笔记(六)---迭代器

《Design Pattens》一书提供有23个设计模式(design patterms)的完整描述,其中iterator 模式定义如下:提供一种方法,使之能够依序巡访某个聚合物(容器)所含的各个元素,而又无需暴露该聚合物的内部表述方式。不论是泛型思维或STL的实际运用,迭代器(iterators)都扮演着重要的角色。STL的中心思想在于:将数据容器(containers) 和算法(algonithms) 分开,彼此独立设计,最后再以一帖胶着剂将它们撮合在一起。 迭代器iterator就是一种智能指针。它

qq_44272681的博客 1029

radsystems的激活(破解)和使用

上个文章讲述了radsystems的下载,但是只有30天的免费使用权,这篇文章将会讲解如何破解激活radsystems。注意:如果不想去官网下载的话,点击安装包的exe文件。不要急,打开我给你们的安装包,点击crack。如果提示done则完成(我的是激活过的)注意:这是8.7版本的。点击generate。

weixin_65144487的博客 3514

C++之STL基础概念、容器、数据结构

全英文是standard template library,标准模板库下面说一下stl的几个特点:1.内置在c++编译中,不需要额外内容2.不需要了解具体实现,只需要会用就可以3.高复用性,可移植性,高性能。

Pxx520Tangtian的博客 1486

芒果YOLO11改进81:主干Backbone篇之DCNv3结构:即插即用|使用pytorch代码实现,并针对YOLO11专门优化模块

芒果YOLO11改进81:主干Backbone篇之DCNv3结构:即插即用|使用pytorch代码实现,并针对YOLO11专门优化模块

包括YOLOv5、YOLOv7、YOLOv8等模型改进 736

一根网线,让整个公司断网,二层环路真实事故复盘

那天晚上 23:47,监控告警突然爆了。核心交换机 CPU 100%。ARP 表暴涨。广播流量飙升。业务系统集体超时。5 分钟后,全公司断网。运维群里一句话:“是不是黑客攻击?但老网工都知道,这种现象只有一种可能:二层环路。

网络技术联盟站 346

跟我学C++中级篇——STL的迭代器

一、迭代器介绍 迭代器(Iterator),是一种抽象的概念,在设计模式中也有这种设计模式,它提供了一种方式,能够依次访问容器的相关元素,并且不需要暴露容器内部的相关细节。说得直白一些,就是提供了一套访问所有容器的相关的抽象。它提供了访问这些容器的最小的公共接口,将算法和容器进行了解耦,并利用迭代器将其二者再进行合理的粘合。 迭代器的比较粗浅的理解方式是把它当作一个普通的指针,而指针一般可以进行++和–操作。从而达到对容器内部元素的逐一访问。但实际上,迭代器比之要复杂许多,因为它是抽象出来,普适几乎所有的容

fpcc的专栏 444

滴滴数据分析80道面试题及参考答案

常见的模型评价指标有准确率、召回率、F1 值、均方误差、均方根误差、R 方等。准确率是指模型预测正确的样本数占总样本数的比例,它反映了模型预测的准确性。召回率是指模型预测为正例的样本中实际为正例的比例,它衡量了模型对正例的捕捉能力。F1 值是准确率和召回率的调和平均数,综合考虑了两者的平衡。均方误差是预测值与真实值之差的平方的平均值,它衡量了模型预测值与真实值的平均偏离程度。均方根误差是均方误差的平方根,与均方误差类似,但更直观地反映了误差的大小。

大模型大数据攻城狮的专栏 1695

STL源码分析目录

SIG STL源码分析 前言 本专栏主要以STL源码剖析分析路线来分析SIGSTL3.0源码. 整个模块准备对学习STL源码剖析之后做一个系统的总结, 这些都是我个人的理解, 如果分析有什么问题欢迎各位大佬们指出. 也很感谢作者以及网络中各个大佬的总结, 让我也能更容易更深刻的理解到STL强大和方便, 也让我对template感受深刻. 以下是我自己对STL版块进行分析. 总共分为六个版块 : 空...

啦啦啦 3637

红队攻防渗透技术实战流程:云安全之云原生安全:特权模式和挂载模式

红队云攻防实战1. 什么是云 1. 什么是云

HACKONE的博客 572

mediasoup源码分析(二十)服务端架构设计

目录 简介 信令服务(房间服务) 调度服务 媒体服务 简介 流媒体服务器大的方向上可以分为上述三个模块。目前行业内都是分布式服务,独立部署。mediasoup信令与媒体之间虽然可以管道通信。但在行业内,服务之间通过管道通信用的少。 一般是rpc、mq,或者传统的tcp。这块licode架构比较不错,licode是信令和媒体服务通过MQ消息队列解耦。 下面介绍一下这三个服务主要功能,当然文中所说也是一家之言。 信令服务(房间服务) 信令服务也称为房间服务。有的企业把信令和房间分开,信..

lcalqf的专栏 1545

【C++STL :vector类 (二) 】C++ Vector迭代器失效避坑指南:原因与解决方案详解

此时迭代器是无效的,++it导致程序崩溃——// 此时迭代器是无效的,++it导致程序崩溃int main()while (it!return 0;运行结果——// 使用第一组数据时,程序可以运行1 3 5// 使用第二组数据时,程序最终会崩溃。

艾莉丝努力练剑的博客,感谢大家一直以来的对艾莉丝的支持和鼓励,uu们如果对C/C++方向感兴趣的话,可以通过艾莉丝主页的微信名片加艾莉丝的好友,和努力练剑的艾莉丝一起加油! 1673

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

[ C++ ] STL---反向迭代器的模拟实现

适配器思想实现反向迭代器

m0_58963318的博客 1534

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

STL-迭代器源码剖析

在接触了STL后,觉得STL就是一个为效率而生的怪物,而且令人惊讶的是它里面的很多算法和模板对于学C++的人来说是非常有价值去剖析的。        迭代器(Iterator)模式--提供一种方法,使之能够依序寻访某个聚合物(容器)所含的各个元素,而又无需暴露该聚合物的内部表达方式。 STL的中心思想在于:将数据容器和算法分开,彼此独立设计,最后再以一贴胶合剂(iterator)将它们撮合在一

如风 2257

STL源码分析之迭代器

前言 迭代器是将算法和容器两个独立的泛型进行调和的一个接口. 使我们不需要关系中间的转化是怎么样的就都能直接使用迭代器进行数据访问. 而迭代器最重要的就是对operator *和operator->进行重载, 使它表现的像一个指针. 类型 迭代器根据移动特性和实施操作被分为5类 input iterator(输入迭代器) : 迭代器所指的内容不能被修改, 只读且只能执行一次读操...

die7024的博客 144

【C++STL :list类 (二) 】序列容器性能的本质:深度剖析 list 与 vector 的迭代器核心奥秘

1、list和vector其实是互补的关系——2、vector任意位置插入和删除效率低插入时有可能需要增容头插、头删还是用list;3、数组比链表更好;4、单纯存东西:vector(顺序表)更优,有头部操作:list。

艾莉丝努力练剑的博客,感谢大家一直以来的对艾莉丝的支持和鼓励,uu们如果对C/C++方向感兴趣的话,可以通过艾莉丝主页的微信名片加艾莉丝的好友,和努力练剑的艾莉丝一起加油! 1624

1.STL源码解析-迭代器Iterator

设计迭代器的时候,需要设计适当的相应型别以及对应的符号重载。而设计适当的迭代器,则是容器的责任。只有容器才知道该设计出怎样的迭代器来遍历自己,并执行迭代器该有的各种行为(前进、后退、取值、取用成员等)。而算法,完全是独立于容器和迭代器之外的,可以自由设计,在设计时以迭代器为对外接口就行了。traits技法广泛用于STL中,它利用“内嵌型别”的编程技巧,与编译器的模板templete参数推导功能,来为C++提供型别识别的能力。

weixin_44477424的博客 1266

STL源码分析之二—迭代器

STL源码分析之二—迭代器 1.Traits编程技巧:   Traits编程技法大量运用在STL实现品中,它利用“内嵌型别”的编程技巧与编译器的template参数推导功能,增强C++未能提供的关于型别认证方面的能力,弥补C++不为强型别语言的遗憾, 例: Template Struct MyIter { Typedef T value_type; T*ptr; MyIt

小小的CODEING的专栏 561

C++ stl库 手写 源码分析

C++ stl库 手写前言序列式关联式容器适配器ListVector 函数dequestringstack queuebitset关联式容器 set multisetmultiset算法库仿函数 前言 stl版本 abcd,四个版本, 接口肯定是一样的 代码复用性强,效率高,通用性高,vector deque 他有六个组件,空间配置器,容器,迭代器,算法,仿函数,容器适配器 容器和算法中间,靠迭代器连接 算法为了通用性,有辅助的东西,让算法通用,也就是使用仿函数 仿函数就是一个对象 容器通过适配器,可以相

hxhxhxhxx的博客 2859

《C++ STL:vector类(下)》:攻克 C++ Vector 的迭代器失效陷阱:从源码层面详解原理与解决方案

【C++ vector迭代器失效问题深度解析】 本文系统分析了C++中vector容器迭代器失效的核心问题和解决方案。主要内容包括: 迭代器失效机制 底层原理:迭代器本质是指针,失效源于指向空间被释放 典型场景:insert/push_back等扩容操作导致旧空间释放 删除操作:erase后元素前移,若删除末尾元素会使迭代器指向end 解决方案对比 Windows(vs)严格检测:操作后必须重置迭代器 Linux(g++)较宽松:部分情况仍可运行但结果不可靠 正确做法:insert/erase后接收返回值更

心向往之,行必能至 1261
上一篇: C++ template 的 type traits 代码
下一篇: grub2 1.95 源码分析之一 —— boot.S 分析及注释
cppgp
博客等级 码龄20年 47粉丝 46原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值