One of the first articles of C++ teaches you list (simulation implementation)

insert image description here

List simulation implementation

member type table
insert image description here

This table lists some member type definitions of the list container in the C++ standard library. These type definitions are to enable list to work with other components of the C++ standard library and to provide some common standard interfaces. The usefulness of each member type:

value_type: This member type represents the data type stored in the list container, that is, the type of the template parameter T.

allocator_type: This member type represents the type of allocator used for memory allocation and management for the container. By default, use allocator<value_type>as allocator.

reference: This member type represents the reference type to the element. For the default allocator, it is value_type&, i.e. a reference to the element.

const_reference: This member type represents a reference type to a constant element. For the default allocator, it is const value_type&, i.e. a reference to the constant element.

pointer: This member type represents the pointer type to the element. For the default allocator, it is value_type*, i.e. a pointer to the element.

const_pointer: This member type represents the pointer type to the constant element. For the default allocator, it is const value_type*, i.e. pointer to constant element.

iterator: This member type is a bidirectional iterator type that can be used to traverse the elements of the container. It can be implicitly converted to const_iterator, allowing elements to be modified while traversing.

const_iterator: This member type is also a bidirectional iterator type, which is used to traverse the elements of the constant container and does not allow modification of the elements.

reverse_iterator: This member type is iteratora reverse iterator that can traverse from the end of the container to the head.

const_reverse_iterator: This member type is const_iteratora reverse iterator for traversing from the end of the constant container to the head.

difference_type: This member type represents the distance between two iterators, usually used ptrdiff_t, is the same as the difference type of the pointer.

size_type: This member type represents the type of non-negative integer, which is usually used size_tto represent the size of the container.

The definition of these member types enables the list container to interact with other C++ standard library components and user-defined code, so as to achieve more general and flexible functions.

list_node node structure definition

Define the node structure of the linked list list_node, which is used to store each element in the linked list. Let's explain what each part means one by one.

template<class T>
struct list_node
{
    
    
    T _data;            // 存储节点的数据
    list_node<T>* _next;  // 指向下一个节点的指针
    list_node<T>* _prev;  // 指向前一个节点的指针

    // 构造函数
    list_node(const T& x = T())
        :_data(x)        // 使用参数 x 初始化 _data
        , _next(nullptr) // 初始化 _next 为 nullptr
        , _prev(nullptr) // 初始化 _prev 为 nullptr
    {
    
    }
};

T _data;: The data stored in the node, the type is a template parameter T, which can be any data type.

list_node<T>* _next;: Pointer to the next node, used to build the linked list structure. Initially set nullptrto indicate that the current node has no successor node.

list_node<T>* _prev;: A pointer to the previous node, also used to build a linked list structure. Initially set nullptrto indicate that the current node has no predecessor node.

Constructor list_node(const T& x = T()): The constructor can receive a parameter xto initialize the data of the node. If no parameters are passed in, an empty node is constructed by default.

Through this node structure, you can create a doubly linked list list, store different types of data in the nodes, and connect the nodes to build the structure of the linked list. This node structure provides the basis for the implementation of linked lists.

std::__reverse_iterator reverse iterator implementation

#pragma once

namespace xzq
{
    
    
	// 复用,迭代器适配器
	template<class Iterator, class Ref, class Ptr>
	struct __reverse_iterator
	{
    
    
		Iterator _cur;
		typedef __reverse_iterator<Iterator, Ref, Ptr> RIterator;

		__reverse_iterator(Iterator it)
			:_cur(it)
		{
    
    }

		RIterator operator++()
		{
    
    
			--_cur;
			return *this;
		}

		RIterator operator--()
		{
    
    
			++_cur;
			return *this;
		}

		Ref operator*()
		{
    
    
			auto tmp = _cur;
			--tmp;
			return *tmp;
		}

		Ptr operator->()
		{
    
    
			return &(operator*());
		}

		bool operator!=(const RIterator& it)
		{
    
    
			return _cur != it._cur;
		}
	};
}

illustrate:

__reverse_iteratorThe class template defines a reverse iterator with three template parameters: Iterator( iterator type ), Ref( reference type ), and Ptr( pointer type ).
_curIs a private member variable that holds the position of the current iterator.
The constructor takes a forward iterator as a parameter and stores it in _cura member variable.
operator++()The increment operator is overloaded to advance the iterator by one position.
operator--()The decrement operator is overloaded to move the iterator one position backwards.
operator*()Overloads the dereference operator to return a reference to the element pointed to by the reverse iterator.
operator->()The member access operator is overloaded to return a pointer to the element pointed to by the reverse iterator.
operator!=()The not equal operator is overloaded to determine whether two reverse iterators are not equal.

This reverse iterator can be used to support iteration from the tail of the container to the head. In the C++ standard library, std::reverse_iterator used to implement similar functionality.

This code implements an iterator adapter. An iterator adapter is a wrapper that provides different functions based on existing iterators, enabling the original iterators to adapt to new usage scenarios.

__reverse_iteratoris a reverse iterator adapter. It encapsulates a forward iterator, but by overloading operators, etc., it can iterate from the end of the container to the head. Such an adapter can make the original forward iterator more convenient when traversing backwards.The reverse iterator function in the following listsimulation implementation needs to be used. Of course, it can also be applied to the simulation implementation of other containers. Depending on the scenario, not all containers can be applied.

list iterator __list_iterator definition

Iterator __list_iterator, used to traverse the nodes in the linked list. Let's explain what each part means one by one.

template<class T, class Ref, class Ptr>
struct __list_iterator
{
    
    
    
	typedef list_node<T> Node;  // 定义一个类型别名 Node,用于表示 list 节点的类型

	typedef __list_iterator<T, Ref, Ptr> iterator;  // 定义一个类型别名 iterator,用于表示 list 迭代器的类型

	typedef bidirectional_iterator_tag iterator_category;  // 定义迭代器的分类,这里是双向迭代器
	
	typedef T value_type;  // 定义元素的类型,即模板参数 T

	typedef Ptr pointer;  // 定义指向元素的指针类型,用于迭代器

	typedef Ref reference;  // 定义对元素的引用类型,用于迭代器

	typedef ptrdiff_t difference_type;  // 定义表示迭代器之间距离的类型

    Node* _node;  // 指向链表中的节点

    __list_iterator(Node* node)
        :_node(node)  // 初始化迭代器,指向给定的节点
    {
    
    }

    bool operator!=(const iterator& it) const
    {
    
    
        return _node != it._node;  // 比较两个迭代器是否不相等
    }

    bool operator==(const iterator& it) const
    {
    
    
        return _node == it._node;  // 比较两个迭代器是否相等
    }

    Ref operator*()
    {
    
    
        return _node->_data;  // 返回当前节点的数据
    }

    Ptr operator->()
    {
    
     
        return &(operator*());  // 返回当前节点数据的地址
    }

    // ++it
    iterator& operator++()
    {
    
    
        _node = _node->_next;  // 迭代器自增,指向下一个节点
        return *this;
    }
    
    // it++
    iterator operator++(int)
    {
    
    
        iterator tmp(*this);  // 创建一个临时迭代器保存当前迭代器
        _node = _node->_next;  // 迭代器自增,指向下一个节点
        return tmp;  // 返回保存的临时迭代器
    }

    // --it
    iterator& operator--()
    {
    
    
        _node = _node->_prev;  // 迭代器自减,指向前一个节点
        return *this;
    }

    // it--
    iterator operator--(int)
    {
    
    
        iterator tmp(*this);  // 创建一个临时迭代器保存当前迭代器
        _node = _node->_prev;  // 迭代器自减,指向前一个节点
        return tmp;  // 返回保存的临时迭代器
    }
};

This iterator structure provides the ability for linked lists to traverse nodes. It can be used to loop through each element of the linked list, providing pointer-like behavior, making it easier to traverse the linked list.

Here is a mention of the classification of iterator types:

Iterators in the C++ Standard Library are divided into five main types, each providing different functionality and supported operations. These types are:

Input Iterator (Input Iterator) : It is only allowed to read elements from the container, but cannot modify the elements in the container. Only operations such as moving one by one, dereferencing, comparing, and comparing for equality are supported. Input iterators are often used in algorithms such as std::find().

Output Iterator : It is only allowed to write elements to the container, but not to read the elements in the container. Operations such as moving elements one by one and writing elements one by one are supported.

Forward Iterator (Forward Iterator) : Similar to the input iterator, but supports multiple dereferences. Forward iterators can be used for operations that require multiple iterations, such as traversing a singly linked list.

Bidirectional Iterator (Bidirectional Iterator) : Based on the forward iterator, it adds the ability to traverse forward. In addition to supporting operations on input iterators, operations such as moving forward and moving elements forward one by one are also supported.

Random Access Iterator (Random Access Iterator) : is the most powerful iterator type. In addition to supporting all operations of forward iterators and bidirectional iterators, pointer-like arithmetic operations such as addition, subtraction, and random access to elements in containers are supported. Random access iterators are often used in data structures that support random access, such as arrays.

In the above code, typedef bidirectional_iterator_tag iterator_category; it means that this iterator is a bidirectional iterator type, so it should support all operations of forward and bidirectional iterators, including moving, dereferencing, comparing, etc. This is to ensure that this iterator listworks properly when traversing container elements of the class.

List class member definition

The following code is the class definition part of the doubly linked list template class list in C++. This class defines some public member types and private member variables to support linked list operations. Let's explain what each part means one by one.

template<class T>
class list
{
    
    
    typedef list_node<T> Node;
public:
    // 定义迭代器类型
    typedef __list_iterator<T, T&, T*> iterator;
    typedef __list_iterator<T, const T&, const T*> const_iterator;

    typedef __reverse_iterator<iterator, T&, T*> reverse_iterator;
    typedef __reverse_iterator<const_iterator, const T&, const T*> const_reverse_iterator;

private:
    Node* _head;
};

typedef list_node<T> Node;: Define an alias Nodethat represents the node type of the linked list list_node<T>.

typedef __list_iterator<T, T&, T*> iterator;: Defines the forward iterator type of the linked list iterator, it uses __list_iterator the structure template, and specifies the corresponding parameter type.

typedef __list_iterator<T, const T&, const T*> const_iterator;: Defines the constant forward iterator type of the linked list const_iterator, which is used to traverse the linked list without modifying the elements of the linked list.

typedef __reverse_iterator<iterator, T&, T*> reverse_iterator;: Defines the reverse iterator type of the linked list reverse_iterator, which traverses from the end of the linked list to the beginning of the linked list.

typedef __reverse_iterator<const_iterator, const T&, const T*> const_reverse_iterator;: Defines a constant reverse iterator type for linked lists const_reverse_iterator.

Node* _head;: The private member variable of the linked list, pointing to the head node of the linked list.

The code in this part defines listthe public member types and private member variables of the class, providing a basis for realizing the operation and management of the linked list.

list member function definition

1.begin()、end()、rbegin()和rend()

const_iterator begin() const
		{
    
    
			return const_iterator(_head->_next);
		}

		const_iterator end() const
		{
    
    
			return const_iterator(_head);
		}

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

		iterator end()
		{
    
    
			return iterator(_head);
		}

		reverse_iterator rbegin()
		{
    
    
			return reverse_iterator(end());
		}

		reverse_iterator rend()
		{
    
    
			return reverse_iterator(begin());
		}

This part of the code is about listthe definition of the iterator member function of the class. They are used to return different types of iterators, allowing the user to iterate over listthe elements of the container.

const_iterator begin() const: This is a constant member function that returns a constant iterator pointing to the first element (node) in the container. Since it is a constant iterator, it is not allowed to modify the elements in the container through it.

const_iterator end() const: This is also a const member function that returns a const iterator pointing to the "post-tail" position at the end of the container, i.e. the position of an element that does not exist. Constant iterators cannot be used to modify elements.

iterator begin(): This is a non-const member function that returns a non-const iterator pointing to the first element (node) in the container. Allows to modify the elements in the container through this iterator.

iterator end(): This is also a non-const member function that returns a non-const iterator that points to the "post-tail" position at the end of the container, that is, the position of an element that does not exist. Non-const iterators can be used to modify elements.

reverse_iterator rbegin(): This is a function that returns a reverse iterator. It end()passes the iterator of the as a parameter to reverse_iteratorthe constructor, thus returning a reverse iterator pointing to the end of the container.

reverse_iterator rend(): This is a function that returns a reverse iterator. It begin()passes the iterator of the to reverse_iteratorthe constructor, thus returning a reverse iterator pointing to the beginning of the container.

The purpose of these functions is to facilitate users to traverse container elements in different situations, including forward traversal and reverse traversal, and using constant or non-constant iterators. Through these iterators, users can easily access and manipulate elements in the list container.

2.empty_init()

void empty_init()
{
    
    
    _head = new Node; // 创建一个新的节点作为链表头部
    _head->_next = _head; // 将头部节点的下一个指针指向自身,表示链表为空
    _head->_prev = _head; // 将头部节点的前一个指针也指向自身,表示链表为空
}

This is lista private member function of the class empty_init()that initializes an empty linked list.

_headThe purpose of this function is to initialize the correct pointer for the head node when creating a new empty linked list, so that the linked list is empty. The head node of the linked list _headis used to identify the starting position and the ending position of the linked list.

In this function, first newcreate a new node as the head of the linked list through the operator. Then, both _nextthe pointer and _prevthe pointer of the head node point to itself, indicating that the linked list is empty. In this case, the head node of the linked list is both the first node and the tail node, forming a circular linked list structure.

In listthe constructor of the class, empty_init()create an empty linked list by calling . This provides a correct basis for operations such as insertion and deletion of the linked list in subsequent operations.

3. Constructor definition

template <class InputIterator>  
list(InputIterator first, InputIterator last)
{
    
    
    empty_init(); // 初始化一个空链表

    while (first != last)
    {
    
    
        push_back(*first); // 将当前迭代器指向的元素添加到链表尾部
        ++first; // 移动迭代器到下一个元素
    }
}

listConstructor template for a class that takes a range of elements and adds those elements to a linked list.
This constructor takes a template parameter InputIteratorthat represents the type of the input iterator. In this way, the constructor can accept different types of iterators, such as ordinary pointers, listiterators of , etc.

In the constructor, first call empty_init()the function to initialize an empty linked list to ensure that the node at the head of the linked list _headis correctly initialized.

Then, use a loop to iterate over the elements within the range of the input iterator. In each loop, push_back()add the element pointed by the current iterator to the end of the linked list through the function. Afterwards, the iterator is moved forward one position so that the next element can be processed.

list()
{
    
    
    empty_init(); // 初始化一个空链表
}

This is listthe no-argument constructor of the class, which is used to create an empty linked list.

This constructor does not accept any parameters, it just initializes the node as an empty linked list when the object is created _head. Calling empty_init()the function will create a _headlinked list containing only nodes, and the _nextand of the node _prevboth point to itself, indicating that the linked list is empty.

list(const list<T>& lt)
{
    
    
    empty_init(); // 初始化一个空链表

    list<T> tmp(lt.begin(), lt.end()); // 使用迭代器从 lt 创建一个临时链表
    swap(tmp); // 交换临时链表和当前链表,完成拷贝操作
}

This is the copy constructor of the class which is used to create a new linked list which is identical listto another already existing linked listlt

In this constructor, empty_init()an empty linked list is first initialized by calling the function, and then a temporary linked list is created tmp. The elements of this temporary linked list are the same as those in the linked list , and are created from the scope of ltthe iterator . ltThen, swap()the current linked list is tmpexchanged with the temporary linked list by calling the function, thus realizing the copy of the linked list.

This method can achieve the effect of copy construction, because in swap()the function, tmpthe resources of the temporary linked list will be handed over to the current linked list, and the temporary linked list tmpwill be destroyed, thus realizing the copy of the content of the linked list.

4.swap

void swap(list<T>& x)
{
    
    
    std::swap(_head, x._head); // 交换两个链表的头结点指针
}

This is lista member function of the class swapthat is used to swap the contents of two linked lists.

In this function, std::swapthe head node pointer of the current linked list is exchanged _headwith xthe head node pointer of another linked list by calling the standard library function. _headThis operation will cause the contents of the two linked lists to be exchanged, but the elements in the linked list are not actually copied, but the structure of the linked list is exchanged.

This exchange operation is usually used when the content of two objects needs to be exchanged, and it can realize the content exchange between two objects without copying data, thereby improving efficiency.

It should be noted that this function only exchanges the head node pointer of the linked list, but the order of elements in the linked list does not change.

5. Destructor definition

~list()
{
    
    
    clear();         // 清空链表中的所有元素
    delete _head;    // 删除头结点
    _head = nullptr; // 将头结点指针置为空指针
}

This is listthe destructor of the class, used to destroy the linked list object.

In this destructor, the member function is first called clear()to clear all elements in the linked list to ensure that all resources are released before deleting the linked list. Then, use deletethe keyword to free the memory of the head node. Finally, set the head node pointer _headas a null pointer to avoid wild pointers.

In this way, when the linked list object is destroyed, the memory it occupies will be released correctly, thereby preventing memory leaks.

6.clear()

void clear()
{
    
    
    iterator it = begin(); // 获取链表的起始迭代器
    while (it != end())    // 遍历链表
    {
    
    
        it = erase(it);    // 使用 erase() 函数删除当前元素,并将迭代器指向下一个元素
    }
}

This is a member function listof the class clear(), which is used to clear all elements in the linked list.

In this function, first get the starting iterator of the linked list begin(), and then traverse all elements in the linked list through a loop. Inside the loop, erase()the function is called to delete the element pointed by the current iterator, and update the iterator to point to the element next to the deleted element. This ensures that all elements in the linked list are removed one by one.

It should be noted that erase()the function returns an iterator pointing to the next element after deleting an element, so it is necessary to update the iterator on each loop iteration in order to continue traversing the linked list correctly.

In short, this clear()function is used to free all elements in the linked list and ensure that the linked list becomes an empty linked list.

7.push_back

void push_back(const T& x)
{
    
    
    Node* tail = _head->_prev; // 获取当前链表的末尾节点
    Node* newnode = new Node(x); // 创建一个新节点,保存新元素 x

    tail->_next = newnode; // 更新末尾节点的下一个指针,指向新节点
    newnode->_prev = tail; // 新节点的前一个指针指向原末尾节点
    newnode->_next = _head; // 新节点的下一个指针指向头节点
    _head->_prev = newnode; // 头节点的前一个指针指向新节点,完成插入操作
}

This is a member function listof class push_back()that is used to add a new element at the end of the linked list.

In this function, first get the end node of the current linked list (the end node _prevpoints to the last element of the linked list), then create a new node newnode, and xstore the new element in the new node. Then, update _nextthe pointer of the end node to point to the new node, and then update _prevthe pointer of the new node to point to the original end node. At the same time, point the pointer of the new node _nextto the head node to complete the connection of the circular linked list. Finally, update the pointer of the head node _prevto point to the new node to ensure that the connection of the linked list is complete.

It should be noted that this function adds a new element at the end of the linked list and does not affect the relative positions of other elements.

8.push_front

void push_front(const T& x)
{
    
    
    insert(begin(), x); // 调用 insert 函数,在头部插入新元素 x
}

This function simply calls insertthe function to xinsert the new element at the head of the linked list.

9.insert

iterator insert(iterator pos, const T& x)
{
    
    
    Node* cur = pos._node; // 获取当前位置的节点
    Node* prev = cur->_prev; // 获取当前位置节点的前一个节点

    Node* newnode = new Node(x); // 创建一个新节点,保存新元素 x

    prev->_next = newnode; // 更新前一个节点的下一个指针,指向新节点
    newnode->_prev = prev; // 新节点的前一个指针指向前一个节点
    newnode->_next = cur; // 新节点的下一个指针指向当前位置节点
    cur->_prev = newnode; // 当前位置节点的前一个指针指向新节点,完成插入操作

    return iterator(newnode); // 返回指向新节点的迭代器
}

In insertthe function, first get the current position node posand its previous node prev, then create a new node newnodeand xstore the new element in the new node. Next, update the pointer of the previous node _nextto point to the new node, and then update _prevthe pointer of the new node to point to the previous node. At the same time, point _nextthe pointer of the new node to the current position node curto complete the insertion operation. Finally, update the pointer of the node at the current position _prevto point to the new node to ensure that the connection of the linked list is complete. Finally, the function returns an iterator pointing to the new node, representing the position after the insertion operation is complete.

10.erase

iterator erase(iterator pos)
{
    
    
    assert(pos != end()); // 断言:确保 pos 不等于链表的结束迭代器

    Node* cur = pos._node; // 获取当前位置的节点
    Node* prev = cur->_prev; // 获取当前位置节点的前一个节点
    Node* next = cur->_next; // 获取当前位置节点的后一个节点

    prev->_next = next; // 更新前一个节点的下一个指针,指向后一个节点
    next->_prev = prev; // 更新后一个节点的前一个指针,指向前一个节点
    delete cur; // 删除当前位置的节点

    return iterator(next); // 返回指向后一个节点的迭代器,表示删除操作完成后的位置
}

This part of the code implements the function of deleting the element at the specified position from the linked list.

In erasethe function, an assert is first used to ensure that the delete position posis not the end iterator of the linked list. Then, get the current position node pos, its previous node prevand next node next. Then, update the pointer of the previous node _nextto make it point to the next node, and update _prevthe pointer of the latter node to make it point to the previous node. In this way, the current position node is disconnected from the linked list. Finally, release the memory space of the node at the current position, and return an iterator pointing to the next node, indicating the position after the deletion operation is completed.

11. pop_back() and pop_front()

void pop_back()
{
    
    
    erase(--end()); // 通过 erase 函数删除链表末尾的元素
}

pop_backeraseThe function realizes the operation of deleting an element from the end of the linked list by moving the end iterator of the linked list forward one position, and then calling the function to delete the element at this position.

void pop_front()
{
    
    
    erase(begin()); // 通过 erase 函数删除链表头部的元素
}

pop_frontThe function directly calls erasethe function to delete the element at the head of the linked list, realizing the operation of deleting an element from the head of the linked list.

These two functions correspond to the operation of deleting elements from the end and head of the linked list respectively, and erasethe deletion operation is completed by calling the function, thereby maintaining the connectivity of the linked list.

12.empty()、size()、front()和back()

bool list<T>::empty() const
{
    
    
    return begin() == end(); // 判断 begin() 是否等于 end() 来确定是否为空
}

typename list<T>::size_t list<T>::size() const
{
    
    
    size_t count = 0;
    for (const_iterator it = begin(); it != end(); ++it)
    {
    
    
        ++count;
    }
    return count; // 遍历链表来计算元素个数
}

typename list<T>::reference list<T>::front()
{
    
    
    assert(!empty()); // 如果链表为空,则抛出断言
    return *begin(); // 返回链表的第一个元素
}

typename list<T>::const_reference list<T>::front() const
{
    
    
    assert(!empty()); // 如果链表为空,则抛出断言
    return *begin(); // 返回链表的第一个元素
}

typename list<T>::reference list<T>::back()
{
    
    
    assert(!empty()); // 如果链表为空,则抛出断言
    return *(--end()); // 返回链表的最后一个元素
}

typename list<T>::const_reference list<T>::back() const
{
    
    
    assert(!empty()); // 如果链表为空,则抛出断言
    return *(--end()); // 返回链表的最后一个元素
}

The above code implements empty()the function to judge whether the linked list is empty, size()the function to get the number of linked list elements, front()the function to get the first element of the linked list, and back()the function to get the last element of the linked list. Note that the assertions in the function are used to ensure that no illegal operations are performed if the linked list is empty.

13.resize

template<class T>
void list<T>::resize(size_t n, const T& val)
{
    
    
    if (n < size()) {
    
    
        iterator it = begin();
        std::advance(it, n); // 定位到新的尾部位置
        while (it != end()) {
    
    
            it = erase(it); // 从尾部截断,删除多余的元素
        }
    }
    else if (n > size()) {
    
    
        insert(end(), n - size(), val); // 插入足够数量的默认值元素
    }
}

If nis less than the size of the current linked list size(), it means you want to reduce the size of the linked list. In this case, the function iterates through the linked list, removing redundant elements starting from the end, until the size of the linked list is equal to n.

First, the function will use to get begin()the starting iterator of the linked list, and then use std::advancethe function to move the iterator forward nby positions so that it points to the new end position.

Next, the function uses erasethe function to remove all elements from the new tail position to the end of the linked list, reducing the size of the linked list to n.

If nis greater than the size of the current linked list, it means you want to increase the size of the linked list. In this case, the function will insert a sufficient number of valelements with value at the end of the linked list until the size of the linked list is equal to n.

The function will use the function to insert elements with a value insertat the end of the linked list , thereby increasing the size of the linked list to .n - size()valn

14. Assignment operator overloading

list<T>& operator=(list<T> lt)
{
    
    
    swap(lt); // 交换当前对象和传入对象的内容
    return *this; // 返回当前对象的引用
}

This is an assignment operator overload function, which uses the copy and exchange (Copy and Swap) technique to achieve the assignment operation.

This is a member function used to assign an list<T> object of a type to the current object.
The parameter lt is passed by value, so list<T>the copy constructor of is called to create a temporary copy.
Then, swap the contents of the current object and the temporary copy by swap(lt)calling the function. swapAfter the exchange, the data of the temporary copy will be assigned to the current object, and the temporary copy will be destroyed. Since swapping is an efficient operation, a large number of data copies can be avoided.
Finally, the function returns a reference to the current object to support continuous assignment operations.
This approach not only avoids the hassle of manually managing memory, but also ensures exception safety, since the temporary copy is properly destroyed at the end of the function.

List simulation to realize all codes

#pragma once

#include <assert.h>
#include <iostream>

namespace xzq
{
    
    
	template<class T>
	struct list_node
	{
    
    
		T _data;
		list_node<T>* _next;
		list_node<T>* _prev;

		list_node(const T& x = T())
			:_data(x)
			, _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> iterator;

		typedef bidirectional_iterator_tag iterator_category;
		typedef T value_type;
		typedef Ptr pointer;
		typedef Ref reference;
		typedef ptrdiff_t difference_type;


		Node* _node;

		__list_iterator(Node* node)
			:_node(node)
		{
    
    }

		bool operator!=(const iterator& it) const
		{
    
    
			return _node != it._node;
		}

		bool operator==(const iterator& it) const
		{
    
    
			return _node == it._node;
		}

		Ref operator*()
		{
    
    
			return _node->_data;
		}

		Ptr operator->()
		{
    
     
			return &(operator*());
		}

		// ++it
		iterator& operator++()
		{
    
    
			_node = _node->_next;
			return *this;
		}
		
		// it++
		iterator operator++(int)
		{
    
    
			iterator tmp(*this);
			_node = _node->_next;
			return tmp;
		}

		// --it
		iterator& operator--()
		{
    
    
			_node = _node->_prev;
			return *this;
		}

		// it--
		iterator operator--(int)
		{
    
    
			iterator tmp(*this);
			_node = _node->_prev;
			return tmp;
		}
	};

	template<class T>
	class list
	{
    
    
		typedef list_node<T> Node;
	public:
		typedef __list_iterator<T, T&, T*> iterator;
		typedef __list_iterator<T, const T&, const T*> const_iterator;

		typedef __reverse_iterator<iterator, T&, T*> reverse_iterator;
		typedef __reverse_iterator<const_iterator, const T&, const T*> const_reverse_iterator;


		const_iterator begin() const
		{
    
    
			return const_iterator(_head->_next);
		}

		const_iterator end() const
		{
    
    
			return const_iterator(_head);
		}

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

		iterator end()
		{
    
    
			return iterator(_head);
		}

		reverse_iterator rbegin()
		{
    
    
			return reverse_iterator(end());
		}

		reverse_iterator rend()
		{
    
    
			return reverse_iterator(begin());
		}

		void empty_init()
		{
    
    
			_head = new Node;
			_head->_next = _head;
			_head->_prev = _head;
		}

		template <class InputIterator>  
		list(InputIterator first, InputIterator last)
		{
    
    
			empty_init();

			while (first != last)
			{
    
    
				push_back(*first);
				++first;
			}
		}

		list()
		{
    
    
			empty_init();
		}

		void swap(list<T>& x)
		{
    
    
			std::swap(_head, x._head);
		}
		list(const list<T>& lt)
		{
    
    
			empty_init();
			list<T> tmp(lt.begin(), lt.end());
			swap(tmp);
		}

		list<T>& operator=(list<T> lt)
		{
    
    
			swap(lt);
			return *this;
		}

		~list()
		{
    
    
			clear();
			delete _head;
			_head = nullptr;
		}

		void clear()
		{
    
    
			iterator it = begin();
			while (it != end())
			{
    
    
				it = erase(it);
			}
		}

		void push_back(const T& x)
		{
    
    
			Node* tail = _head->_prev;
			Node* newnode = new Node(x);

			tail->_next = newnode;
			newnode->_prev = tail;
			newnode->_next = _head;
			_head->_prev = newnode;

			//insert(end(), x);
		}

		void push_front(const T& x)
		{
    
    
			insert(begin(), x);
		}

		iterator insert(iterator pos, const T& x)
		{
    
    
			Node* cur = pos._node;
			Node* prev = cur->_prev;

			Node* newnode = new Node(x);

			prev->_next = newnode;
			newnode->_prev = prev;
			newnode->_next = cur;
			cur->_prev = newnode;

			return iterator(newnode);
		}

		void pop_back()
		{
    
    
			erase(--end());
		}

		void pop_front()
		{
    
    
			erase(begin());
		}

		iterator erase(iterator pos)
		{
    
    
			assert(pos != end());

			Node* cur = pos._node;
			Node* prev = cur->_prev;
			Node* next = cur->_next;

			prev->_next = next;
			next->_prev = prev;
			delete cur;

			return iterator(next);
		}

		bool list<T>::empty() const
		{
    
    
			return begin() == end(); // 判断 begin() 是否等于 end() 来确定是否为空
		}

		typename list<T>::size_t list<T>::size() const
		{
    
    
			size_t count = 0;
			for (const_iterator it = begin(); it != end(); ++it)
			{
    
    
				++count;
			}
			return count; // 遍历链表来计算元素个数
		}

		typename list<T>::reference list<T>::front()
		{
    
    
			assert(!empty()); // 如果链表为空,则抛出断言
			return *begin(); // 返回链表的第一个元素
		}

		typename list<T>::const_reference list<T>::front() const
		{
    
    
			assert(!empty()); // 如果链表为空,则抛出断言
			return *begin(); // 返回链表的第一个元素
		}

		typename list<T>::reference list<T>::back()
		{
    
    
			assert(!empty()); // 如果链表为空,则抛出断言
			return *(--end()); // 返回链表的最后一个元素
		}

		typename list<T>::const_reference list<T>::back() const
		{
    
    
			assert(!empty()); // 如果链表为空,则抛出断言
			return *(--end()); // 返回链表的最后一个元素
		}
		void resize(size_t n, const T& val = T())
		{
    
    
			if (n < size()) {
    
    
				iterator it = begin();
				std::advance(it, n);
				while (it != end()) {
    
    
					it = erase(it); // 从尾部截断,删除多余的元素
				}
			}
			else if (n > size()) {
    
    
				insert(end(), n - size(), val); // 插入足够数量的默认值元素
			}
		}
	private:
		Node* _head;
	};
}

The difference between list and vector

By simulating the implementation of listand vector, you can better understand the differences and characteristics between them. These two are sequential containers in the C++ standard library, but they have very different internal implementations and usage scenarios.

Underlying implementation:

listUsually a doubly linked list, each node contains data and pointers to the previous and next nodes. This makes inserts and deletes at any location efficient, but random access and memory footprint can be relatively poor.
vectorIt is a dynamic array whose elements are stored contiguously in memory. This makes random access very efficient, but insertion and deletion operations may require moving a large number of elements, which is inefficient.

Insertion and deletion operations:

In list, insertion and deletion operations are efficient, both at any position in the container and at the beginning and end. This makes it listideal when frequent insertion and deletion operations are required.
In vector, insertion and deletion operations may require moving elements, especially in the middle or beginning of the container. vectorTherefore, it may not be as listefficient when a large number of insertion and deletion operations are involved .

random access:

listRandom access is not supported, that is, elements cannot be directly accessed through indexes, and must be traversed one by one through iterators.
vectorSupport random access, you can quickly access elements through indexes, and have good random access performance.

Memory usage:

Due to listthe use of linked lists to store elements, each node requires additional pointers to point to the previous and next nodes, which may result in more memory usage.
vectorIt is stored contiguously in memory and usually takes up less memory.

Iterator invalidation:

In list, insertion and deletion operations do not invalidate iterators because the relationships between nodes do not change.
In vector, insertion and deletion operations may cause memory reallocation, thereby invalidating the original iterator.

To sum up, if you need to perform frequent insertion and deletion operations, but do not have particularly high requirements for random access performance, then using listis a good choice. And if you pay more attention to random access performance, you can choose to use it vector. Of course, in actual development, it is also necessary to weigh which container to use according to the specific situation.

epilogue

Interested friends can pay attention to the author, if you think the content is good, please give a one-click triple link, you crab crab! ! !
It is not easy to make, please point out if there are any inaccuracies
Thank you for your visit, UU watching is the motivation for me to persevere.
With the catalyst of time, let us all become better people from each other! ! !
(The 128-day anniversary of creation, I haven't figured out how to share it yet, I will write it next time)

Guess you like

Origin blog.csdn.net/kingxzq/article/details/132256699