The use of [C/C++ -STL]list and the failure of vector and list iterators

1, List introduction
What is a list

template < class T, class Alloc = allocator<T> > class list;

This is the definition given in the document
So what is a List?

List is a sequence container that allows fixed time insertion and erasure operations to be performed anywhere in the sequence, and iterates in two directions.
They are similar to forward_list is very similar: the main difference is forward_list objects are single linked lists, so they can only iterate forward in exchange for smaller and more efficient
Compared with other basic standard sequence containers (array, vector and deque), linked lists usually perform better in inserting, extracting and moving elements anywhere in the container (iterators have been obtained) and in algorithms that use these elements heavily, such as sorting algorithms
Compared with other sequence containers, list and forward_ The main disadvantage of lists is that they cannot directly access elements through location; For example, to access the sixth element in the list, you must iterate from a known location (such as start or end), which takes linear time over the distance between these locations. They also consume some extra memory to keep the link information associated with each element (which can be an important factor in a large list of small elements).
List document introduction

2, List structure introduction

The List container is implemented as a double linked List; Double linked lists can store each element they contain in a different, unrelated storage location. Internally, the order is maintained by association with each element, which is a link to the element before it and a link to the element after it.

3, Use of List
3.1 structure of list

list() construct an empty list
The list constructed by list (size_type n, const value_type & Val = value_type()) contains n elements with value val
List (const list & x) copy constructor
list (InputIterator first, InputIterator last) constructs a list with elements in the [first, last) interval

	list<int> l;
	list<int> li(7,0);
	list<int> v(li);
	list<int>v1(li.begin(), li.end());
	for (auto o : v) {
		cout << 0 << " ";
	}
	cout << endl;
	for (auto o : li) {
		cout << 0 << " ";
	}
	cout << endl;

l call parameterless to construct new an empty object,
li call new with parameters to construct a parameterized object that initializes n var parameters,
v copies the data in to its own memory through the copy constructor,
v1 initializes itself with the [begin(), end()) left closed and right open interval structure of li.
3.2 iterator of list

begin +end
Returns the iterator of the first element + returns the iterator of the next position of the last element
rbegin +rend
Return the reverse_iterator of the first element, that is, the end position, and return the reverse_iterator of the next position of the last element, that is, the begin position

Because the memory space of the list is not continuous, but each node saves the addresses of the previous node and the next node, the list first points to the location of the first node when using the iterator. Because the addresses of the previous node and the next node are saved, both + + and - take the address of the next or previous node pointed to by this node

  1. begin and end are forward iterators. Perform + + operations on the iterator, and the iterator moves backward
  2. rbegin(end) and rend(begin) are reverse iterators. Perform + + operations on the iterator, and the iterator moves forward

3.4 list capacity

Empty checks whether the list is empty. If yes, it returns true; otherwise, it returns false
size returns the number of valid nodes in the list

	list<int> l;
	list<int> li(7);


	std::cout << l.empty() << endl;
	std::cout << li.empty() << endl;

	std::cout << l.size() << endl;
	std::cout << li.size() << endl;

Because l is an empty object called to construct new without parameters, empty is 1 and size() is 1
li is initialized with seven var s and constructed with parameters, so empty is 0 and size() is 7
3.5 list element access

front return list Reference to the value in the first node of the
back return list Reference to the value in the last node of the
	list<int> l;
	list<int> li(7);


	std::cout << li.front() << endl;
	std::cout << li.back() << endl;

front is the address of the first node of the double linked list,
back is the address of the last node in the double linked list

3.6 list modifiers

push_front inserts an element with value val before the first element of the list
pop_front deletes the first element in the list
push_back inserts an element with value val at the end of the list
pop_back deletes the last element in the list
insert inserts an element with the value val in the list position
erase deletes the element at the position of the list
swap exchanges elements in two list s
clear clears the valid elements in the list

list<int> l(4,2);
	list<int> li(6,1);
	for (auto o : li) {
		std::cout << o << " ";
	}std::cout << endl;
	li.push_front(5);

	for (auto o : li) {
		std::cout << o << " ";
	}std::cout << endl;
	li.pop_front();
	for (auto o : li) {
		std::cout << o << " ";
	}std::cout << endl;
	li.push_back(2);
	for (auto o : li) {
		std::cout << o << " ";
	}std::cout << endl;
	li.pop_back();
	for (auto o : li) {
		std::cout << o << " ";
	}std::cout << endl;
	li.insert(li.begin(), 3);
	for (auto o : li) {
		std::cout << o << " ";
	}std::cout << endl;
	li.erase(li.begin());
	for (auto o : li) {
		std::cout << o << " ";
	}std::cout << endl;
	l.swap(li);
	for (auto o : l) {
		std::cout << o << " ";
	}std::cout << endl;
	for (auto o : li) {
		std::cout << o << " ";
	}std::cout << endl;
	li.clear();
	for (auto o : li) {
		std::cout << o << " ";
	}std::cout << endl;

Initialize li to 6 1s, l to 4 2push_front s, insert the element pop_front with value val before the first element in the list, delete the first element push_back in the list, insert the element pop_back with value val at the end of the list, delete the last element in the list, and insert it in list begin() Insert the element with value val in position erase delete the element in list position swap exchange the elements in two lists clear clear the valid elements in the list
3.7 list iterator failure

list<int> l(4,2);
	list<int> li(6,1);
	li.push_back(10);
	li.push_back(30);
	li.push_back(40);
	li.push_back(50);
	
	auto it = find(li.begin(), li.end(), 10);
	li.erase(it);
	cout << *it << endl;


Why is an error reported when * it is output?

Because the node will release the pos and become a wild pointer after deleting the pos, the output pos will report an error as an invalid parameter.
Will the iterator fail when insert() inserts data?
The answer is no, because unlike vector, the memory space in list is continuous. If there is not enough space in insert(), it will open up new space and release the old space, because pos points to
Because of the old space, pos will fail. However, the storage space of list is not continuous. When nsert(), it will not open up a new space, but will only open up a new space for the new node to point to the previous node of pos and pos node. Therefore, without space release, there will be no iterator failure

The bottom layer of vector is a physical continuous array. It may be expanded. This may lead to the problem of wild pointer. If it is not expanded, the data will be moved, and the meaning of pos will change.
list is an independent node. Add a new node in front of pos. POS still points to this node. It will not become one, and its meaning has not changed.

Tags: C++ data structure linked list list STL

Posted on Tue, 23 Nov 2021 05:06:22 -0500 by wendu