C++:模拟实现list及迭代器类模板优化方法

简介: C++:模拟实现list及迭代器类模板优化方法

本篇模拟实现简单的list和一些其他注意的点

迭代器

如下所示是利用拷贝构造将一个链表中的数据挪动到另外一个链表中,构造两个相同的链表

list(const list<T>& lt)
{
  emptyinit();
  for (auto e : lt)
  {
    push_back(e);
  }
}
void test_list1()
{
  list<int> lt;
  lt.push_back(1);
  lt.push_back(2);
  lt.push_back(3);
  lt.push_back(4);
  lt.push_back(5);
  list<int> l2(lt);
}

lt作为形参,传引用可以提高传参的效率,同时应该加上const修饰来保证不会因为不小心修改了形参导致外部的实参也被修改,这样的结果是不应该的,因此就要加const把这个形参变成一个const对象

而问题又来了,const对象要使用的是const迭代器,而前面没有写const迭代器,因此这里就引入了const迭代器的实现

从vector的模拟实现中,看似似乎只需要在原来的迭代器的基础上加上一个const即可,但事实上:

const迭代器和普通迭代器是两种不同的迭代器,不能直接在普通的迭代器后面加const,原因?

要解决这个问题,先重新回顾一下vector中const迭代器的定义流程:

对比vector的迭代器,vector中的迭代器const版本和非const版本直接在非const版本后面加const使它变成const迭代器即可,这样在调用的时候就可以直接进行调用

iterator的定义,const版本就是在指针前面加上const,这样返回的就是const修饰的指针,因此就可以做到通过该迭代器只读,不可修改的作用

这里的迭代器本质上就是指针在底层进行访问,然后我们定义一个const指针,使得const指针就不能对指针指向的内容进行修改了

下面仿照vector修改的原理修改list

要修改的部分其实就是下面的代码:

iterator begin()
{
  return iterator(_head->_next);
}
iterator end()
{
  return iterator(_head);
}

在函数后加const很简单,但是核心是要把返回值也定义为const指针版本,这个过程要如何实现?

由于这里是把iterator封装成了一个类进行的实现,因此需要重新封装一个类进行实现

template <class T>
  struct __list_iterator
  {
    typedef list_node<T> Node;
    typedef  __list_iterator<T> self;
    // 成员
    Node* _node;
    __list_iterator(Node* node)
      :_node(node)
    {}
    self& operator++()
    {
      _node = _node->_next;
      return *this;
    }
    self& operator--()
    {
      _node = _node->_prev;
      return *this;
    }
    self operator++(int)
    {
      self tmp(*this);
      _node = _node->_next;
      return tmp;
    }
    self operator--(int)
    {
      self tmp(*this);
      _node = _node->_prev;
      return tmp;
    }
    T& operator*()
    {
      return _node->_data;
    }
    T* operator->()
    {
      return &_node->_data;
    }
    bool operator==(const self& pos)
    {
      return _node == pos._node;
    }
    bool operator!=(const self& pos)
    {
      return !(*this == pos);
    }
  };
  template <class T>
  struct __list_const_iterator
  {
    typedef list_node<T> Node;
    typedef  __list_const_iterator<T> self;
    // 成员
    Node* _node;
    __list_const_iterator(Node* node)
      :_node(node)
    {}
    self& operator++()
    {
      _node = _node->_next;
      return *this;
    }
    self& operator--()
    {
      _node = _node->_prev;
      return *this;
    }
    self operator++(int)
    {
      self tmp(*this);
      _node = _node->_next;
      return tmp;
    }
    self operator--(int)
    {
      self tmp(*this);
      _node = _node->_prev;
      return tmp;
    }
    const T& operator*()
    {
      return _node->_data;
    }
    const T* operator->()
    {
      return &_node->_data;
    }
    bool operator==(const self& pos)
    {
      return _node == pos._node;
    }
    bool operator!=(const self& pos)
    {
      return !(*this == pos);
    }
  };

但事实上,这两份代码只有很少的地方有区别,更多的内容都是相同的,这样是不满足较好的代码风格,因此在stl源码中,使用了模板对这两个类进行了封装

改进版本如下:

template <class T, class Ref, class Ptr >
  struct __list_iterator
  {
    typedef list_node<T> Node;
    typedef  __list_iterator<T, Ref, Ptr> self;
    // 成员
    Node* _node;
    __list_iterator(Node* node)
      :_node(node)
    {}
    self& operator++()
    {
      _node = _node->_next;
      return *this;
    }
    self& operator--()
    {
      _node = _node->_prev;
      return *this;
    }
    self operator++(int)
    {
      self tmp(*this);
      _node = _node->_next;
      return tmp;
    }
    self operator--(int)
    {
      self tmp(*this);
      _node = _node->_prev;
      return tmp;
    }
    Ref operator*()
    {
      return _node->_data;
    }
    Ptr operator->()
    {
      return &_node->_data;
    }
    bool operator==(const self& pos)
    {
      return _node == pos._node;
    }
    bool operator!=(const self& pos)
    {
      return !(*this == pos);
    }
  };
  template <class T>
  class list
  {
    void emptyinit()
    {
      _head = new Node();
      _head->_next = _head;
      _head->_prev = _head;
      _size = 0;
    }
  public:
    typedef list_node<T> Node;
    typedef __list_iterator<T, T&, T*> iterator;
    typedef __list_iterator<T, const T&, const T*> const_iterator;
    // 构造函数 
    list()
    {
      emptyinit();
    }
    // 拷贝构造
    list(const list<T>& lt)
    {
      emptyinit();
      auto it = lt.begin();
      //*it = 30;
    }
    void push_back(const T& x)
    {
      insert(end(), x);
    }
    void push_front(const T& x)
    {
      insert(begin(), x);
    }
    // head     tail->prev  tail
    void pop_back()
    {
      erase(--end());
    }
    void pop_front()
    {
      erase(begin());
    }
    iterator begin()
    {
      return iterator(_head->_next);
    }
    iterator end()
    {
      return iterator(_head);
    }
    const_iterator begin() const
    {
      return const_iterator(_head->_next);
    }
    const_iterator end() const
    {
      return const_iterator(_head);
    }
    iterator insert(iterator pos, const T& x)
    {
      Node* cur = pos._node;
      Node* prev = cur->_prev;
      Node* newnode = new Node(x);
      //        newnode
      //   prev         cur
      prev->_next = newnode;
      newnode->_prev = prev;
      newnode->_next = cur;
      cur->_prev = newnode;
      return iterator(newnode);
    }
    iterator erase(iterator pos)
    {
      Node* cur = pos._node;
      Node* prev = cur->_prev;
      Node* next = cur->_next;
      // prev cur next
      prev->_next = cur->_next;
      next->_prev = cur->_prev;
      return iterator(next);
    }
  private:
    Node* _head;
    size_t _size;
  };

这里引入了类模板的概念,简单来说,当需要调用const类型时就会模板实例化出一个const版本的迭代器,再进行相关的操作,这样的操作可以避免代码冗余,也是模板的强大之处

模拟实现

#pragma once
// 实现的是双向循环链表,链表中应该包含节点类和迭代器类,节点类用于从内存中申请节点,迭代器类用于获取节点指针
namespace mylist
{
  // 把节点进行封装,可以动态获取一个节点
  template <class T>
  struct list_node
  {
    // 成员
    list_node<T>* _next;
    list_node<T>* _prev;
    T _data;
    // 成员函数
    list_node(const T& val = T())
      :_data(val)
      , _next(nullptr)
      , _prev(nullptr)
    {}
  };
  // 对迭代器进行封装,使得外界看到的是迭代器
  // 迭代器当中存储的是某个节点的指针
  // 可以对迭代器进行各项操作
  template <class T, class Ref, class Ptr >
  struct __list_iterator
  {
    typedef list_node<T> Node;
    typedef  __list_iterator<T, Ref, Ptr> self;
    // 成员
    Node* _node;
    __list_iterator(Node* node)
      :_node(node)
    {}
    self& operator++()
    {
      _node = _node->_next;
      return *this;
    }
    self& operator--()
    {
      _node = _node->_prev;
      return *this;
    }
    self operator++(int)
    {
      self tmp(*this);
      _node = _node->_next;
      return tmp;
    }
    self operator--(int)
    {
      self tmp(*this);
      _node = _node->_prev;
      return tmp;
    }
    Ref operator*()
    {
      return _node->_data;
    }
    Ptr operator->()
    {
      return &_node->_data;
    }
    bool operator==(const self& pos)
    {
      return _node == pos._node;
    }
    bool operator!=(const self& pos)
    {
      return !(*this == pos);
    }
  };
  // 适配器 -- 复用
  template <class T, class Ref, class Ptr >
  struct __reverse_iterator
  {
    typedef list_node<T> Node;
    typedef  __reverse_iterator<T, Ref, Ptr> self;
    // 成员
    Node* _node;
    __reverse_iterator(Node* node)
      :_node(node)
    {}
    self& operator++()
    {
      _node = _node->_prev;
      return *this;
    }
    self& operator--()
    {
      _node = _node->_next;
      return *this;
    }
    self operator++(int)
    {
      self tmp(*this);
      _node = _node->_prev;
      return tmp;
    }
    self operator--(int)
    {
      self tmp(*this);
      _node = _node->_next;
      return tmp;
    }
    Ref operator*()
    {
      return _node->_data;
    }
    Ptr operator->()
    {
      return &_node->_data;
    }
    bool operator==(const self& pos)
    {
      return _node == pos._node;
    }
    bool operator!=(const self& pos)
    {
      return !(*this == pos);
    }
  };
  template <class T>
  class list
  {
    void emptyinit()
    {
      _head = new Node();
      _head->_next = _head;
      _head->_prev = _head;
      _size = 0;
    }
  public:
    typedef list_node<T> Node;
    typedef __list_iterator<T, T&, T*> iterator;
    typedef __list_iterator<T, const T&, const T*> const_iterator;
    typedef __reverse_iterator<T, T&, T*> reverse_iterator;
    typedef __reverse_iterator<T, const T&, const T*> const_reverse_iterator;
    // 构造函数 
    list()
    {
      emptyinit();
    }
    // 拷贝构造
    list(const list<T>& lt)
    {
      emptyinit();
      auto it = lt.begin();
      //*it = 30;
    }
    void push_back(const T& x)
    {
      insert(end(), x);
    }
    void push_front(const T& x)
    {
      insert(begin(), x);
    }
    // head     tail->prev  tail
    void pop_back()
    {
      erase(--end());
    }
    void pop_front()
    {
      erase(begin());
    }
    iterator begin()
    {
      return iterator(_head->_next);
    }
    iterator end()
    {
      return iterator(_head);
    }
    const_iterator begin() const
    {
      return const_iterator(_head->_next);
    }
    const_iterator end() const
    {
      return const_iterator(_head);
    }
    reverse_iterator rbegin()
    {
      return reverse_iterator(_head->_prev);
    }
    reverse_iterator rend()
    {
      return reverse_iterator(_head);
    }
    const_reverse_iterator rbegin() const
    {
      return const_reverse_iterator(_head->_prev);
    }
    const_reverse_iterator rend() const
    {
      return const_reverse_iterator(_head);
    }
    iterator insert(iterator pos, const T& x)
    {
      Node* cur = pos._node;
      Node* prev = cur->_prev;
      Node* newnode = new Node(x);
      //        newnode
      //   prev         cur
      prev->_next = newnode;
      newnode->_prev = prev;
      newnode->_next = cur;
      cur->_prev = newnode;
      return iterator(newnode);
    }
    iterator erase(iterator pos)
    {
      Node* cur = pos._node;
      Node* prev = cur->_prev;
      Node* next = cur->_next;
      // prev cur next
      prev->_next = cur->_next;
      next->_prev = cur->_prev;
      return iterator(next);
    }
  private:
    Node* _head;
    size_t _size;
  };
  void test_list1()
  {
    list<int> lt;
    lt.push_back(1);
    lt.push_back(2);
    lt.push_back(3);
    lt.push_back(4);
    lt.push_back(5);
    cout << "正序" << endl;
    for (auto e : lt)
    {
      cout << e << " ";
    }
    cout << endl;
    cout << "逆序" << endl;
    auto rit = lt.rbegin();
    while (rit != lt.rend())
    {
      cout << *rit << " ";
      rit++;
    }
    cout << endl;
  }
}


相关文章
|
1月前
|
API C++ Windows
Visual C++运行库、.NET Framework和DirectX运行库的作用及常见问题解决方案,涵盖MSVCP140.dll丢失、0xc000007b错误等典型故障的修复方法
本文介绍Visual C++运行库、.NET Framework和DirectX运行库的作用及常见问题解决方案,涵盖MSVCP140.dll丢失、0xc000007b错误等典型故障的修复方法,提供官方下载链接与系统修复工具使用指南。
500 2
|
1月前
|
缓存 算法 程序员
C++STL底层原理:探秘标准模板库的内部机制
🌟蒋星熠Jaxonic带你深入STL底层:从容器内存管理到红黑树、哈希表,剖析迭代器、算法与分配器核心机制,揭秘C++标准库的高效设计哲学与性能优化实践。
C++STL底层原理:探秘标准模板库的内部机制
|
2月前
|
存储 缓存 监控
用 C++ 红黑树给公司电脑监控软件的日志快速排序的方法
本文介绍基于C++红黑树算法实现公司监控电脑软件的日志高效管理,利用其自平衡特性提升日志排序、检索与动态更新效率,并结合实际场景提出优化方向,增强系统性能与稳定性。
117 4
|
5月前
|
存储 算法 安全
c++模板进阶操作——非类型模板参数、模板的特化以及模板的分离编译
在 C++ 中,仿函数(Functor)是指重载了函数调用运算符()的对象。仿函数可以像普通函数一样被调用,但它们实际上是对象,可以携带状态并具有更多功能。与普通函数相比,仿函数具有更强的灵活性和可扩展性。仿函数通常通过定义一个包含operator()的类来实现。public:// 重载函数调用运算符Add add;// 创建 Add 类的对象// 使用仿函数return 0;
205 0
|
5月前
|
人工智能 机器人 编译器
c++模板初阶----函数模板与类模板
class 类模板名private://类内成员声明class Apublic:A(T val):a(val){}private:T a;return 0;运行结果:注意:类模板中的成员函数若是放在类外定义时,需要加模板参数列表。return 0;
157 0
|
5月前
|
存储 编译器 程序员
c++的类(附含explicit关键字,友元,内部类)
本文介绍了C++中类的核心概念与用法,涵盖封装、继承、多态三大特性。重点讲解了类的定义(`class`与`struct`)、访问限定符(`private`、`public`、`protected`)、类的作用域及成员函数的声明与定义分离。同时深入探讨了类的大小计算、`this`指针、默认成员函数(构造函数、析构函数、拷贝构造、赋值重载)以及运算符重载等内容。 文章还详细分析了`explicit`关键字的作用、静态成员(变量与函数)、友元(友元函数与友元类)的概念及其使用场景,并简要介绍了内部类的特性。
249 0
|
7月前
|
编译器 C++ 容器
【c++11】c++11新特性(上)(列表初始化、右值引用和移动语义、类的新默认成员函数、lambda表达式)
C++11为C++带来了革命性变化,引入了列表初始化、右值引用、移动语义、类的新默认成员函数和lambda表达式等特性。列表初始化统一了对象初始化方式,initializer_list简化了容器多元素初始化;右值引用和移动语义优化了资源管理,减少拷贝开销;类新增移动构造和移动赋值函数提升性能;lambda表达式提供匿名函数对象,增强代码简洁性和灵活性。这些特性共同推动了现代C++编程的发展,提升了开发效率与程序性能。
287 12
|
8月前
|
编译器 C++
模板(C++)
本内容主要讲解了C++中的函数模板与类模板。函数模板是一个与类型无关的函数家族,使用时根据实参类型生成特定版本,其定义可用`typename`或`class`作为关键字。函数模板实例化分为隐式和显式,前者由编译器推导类型,后者手动指定类型。同时,非模板函数优先于同名模板函数调用,且模板函数不支持自动类型转换。类模板则通过在类名后加`&lt;&gt;`指定类型实例化,生成具体类。最后,语录鼓励大家继续努力,技术不断进步!
|
8月前
|
编译器 C++
类和对象(下)C++
本内容主要讲解C++中的初始化列表、类型转换、静态成员、友元、内部类、匿名对象及对象拷贝时的编译器优化。初始化列表用于成员变量定义初始化,尤其对引用、const及无默认构造函数的类类型变量至关重要。类型转换中,`explicit`可禁用隐式转换。静态成员属类而非对象,受访问限定符约束。内部类是独立类,可增强封装性。匿名对象生命周期短,常用于临时场景。编译器会优化对象拷贝以提高效率。最后,鼓励大家通过重复练习提升技能!
|
安全 Java
java线程之List集合并发安全问题及解决方案
java线程之List集合并发安全问题及解决方案
1341 1
下一篇
oss云网关配置