Skip to content

Commit b793ce0

Browse files
committed
C++STL分享
1 parent ff5988c commit b793ce0

File tree

3 files changed

+267
-0
lines changed

3 files changed

+267
-0
lines changed

C++ STL.md

Lines changed: 265 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,265 @@
1+
# C++ STL概述
2+
3+
4+
5+
## stl六大组件
6+
7+
1.容器
8+
9+
2.迭代器
10+
11+
3.分配器
12+
13+
4.算法
14+
15+
5.仿函数
16+
17+
6.适配器
18+
19+
​ 其中分配器负责容器的内存管理,迭代器提供了访问容器元素的方法,容器用来存放元素,算法用来处理容器中的数据。
20+
21+
​ STL采用的编程方法GP,和OOP不同。OOP把数据和处理数据的方法组合在一个类中,而GP尝试将数据和方法分开。STL的数据存放在容器中,而处理数据的方法放在算法中,而迭代器作为沟通容器和算法的桥梁。
22+
23+
24+
25+
## 分配器
26+
27+
在我们创建一个对象时,会有两步操作:
28+
29+
1.申请对象所需要的内存空间
30+
31+
2.构造对象。
32+
33+
当我们销毁一个对象时,也有两步操作:
34+
35+
1.析构对象,
36+
37+
2 释放给对象分配的空间。
38+
39+
而分配器的主要功能就是内存空间的分配和回收,对象的构造和析构。
40+
41+
### 内存空间的分配和回收
42+
43+
```C++
44+
//申请空间
45+
template <class T>
46+
T* allocator<T>::allocate()
47+
{
48+
  return static_cast<T*>(::operator new(sizeof(T)));
49+
}
50+
template <class T>
51+
T* allocator<T>::allocate(size_type n)
52+
{
53+
  if (n == 0)
54+
    return nullptr;
55+
  return static_cast<T*>(::operator new(n * sizeof(T)));
56+
}
57+
template <class T>
58+
59+
//释放空间
60+
void allocator<T>::deallocate(T* ptr)
61+
{
62+
  if (ptr == nullptr)
63+
    return;
64+
  ::operator delete(ptr);
65+
}
66+
```
67+
68+
### 对象构建和析构
69+
70+
```
71+
//创建对象
72+
template <class Ty>
73+
void construct(Ty* ptr)
74+
{
75+
  ::new ((void*)ptr) Ty();
76+
}
77+
template <class Ty1, class Ty2>
78+
void construct(Ty1* ptr, const Ty2& value)
79+
{
80+
  ::new ((void*)ptr) Ty1(value);
81+
}
82+
//析构对象
83+
template <class Ty>
84+
void destroy (Ty* pointer)
85+
{
86+
  if (pointer != nullptr)
87+
  {
88+
    pointer->~Ty();
89+
  }
90+
}
91+
```
92+
93+
## 迭代器 Iterators
94+
95+
迭代器是一种设计理念:
96+
迭代器的提供了一个遍历容器内部所有元素的接口,使得可以在不暴露容器内部实现的情况下,通过迭代器访问容器的元素。
97+
除此之外,STL中迭代器一个最重要的作用就是作为容器与STL算法的粘结剂,只要容器提供迭代器的接口,不同的容器就可以使用同一套算法代码。
98+
99+
100+
101+
迭代器重载了++ -- * []等运算符,使得我们可以使用迭代器访问容器,每种容器都定义了自己的迭代器,迭代器根据容器的内部构造的不同实现细节也不一样。
102+
103+
容器都包含两个迭代器成员:
104+
105+
begin():指向容器首元素的迭代器;
106+
107+
end():指向容器最后一个元素后的迭代器,尾后迭代器。
108+
109+
### list中的迭代器:
110+
111+
```C++
112+
typedef T value_type;
113+
typedef list_iterator<T> self;
114+
base_ptr node_;
115+
reference operator*() const
116+
{
117+
return node_->value;
118+
}
119+
pointer operator->() const
120+
{
121+
return &(operator*());
122+
}
123+
self& operator++()
124+
{
125+
MYSTL_DEBUG(node_ != nullptr);
126+
node_ = node_->next;
127+
return *this;
128+
}
129+
self& operator--()
130+
{
131+
MYSTL_DEBUG(node_ != nullptr);
132+
node_ = node_->prev;
133+
return *this;
134+
}
135+
```
136+
137+
### 迭代器的分类
138+
139+
input_iterator(输入迭代器):提供对数据的只读访问;
140+
141+
output_iterator(输出迭代器): 提供对数据的只写访问;
142+
143+
forward_iterator (前向迭代器):提供读写操作,并且能向前推进迭代器;
144+
145+
bidirectional_iterator双向迭代器:提供读写操作,并且能向前向后操作;
146+
147+
random_access_iterator(随机访问迭代器):提供读写操作,并能以跳跃的方式访问容器内的任意数据。
148+
149+
## 容器
150+
151+
容器分为顺序容器和关联容器:
152+
顺序容器提供了控制元素存储和访问顺序的能力,这种顺序不依赖于元素的值,而是与元素加入容器时的位置有关系。
153+
154+
而关联容器时根据关键字的值来存储元素。
155+
156+
顺序容器有:
157+
158+
vector
159+
160+
deque
161+
162+
list
163+
164+
forward_list
165+
166+
array
167+
168+
string
169+
170+
关联容器:
171+
172+
map
173+
set
174+
multimap
175+
multiset
176+
unordered_map
177+
unordered_ set
178+
unordered_multimap
179+
unordered_multiset
180+
181+
### vector
182+
183+
Vector中元素的存储方式是顺序存储,并且vector的存储空间是动态的,随着元素的加入,它的内部机制会自动扩充空间以容纳新元素。
184+
185+
vector结构体
186+
187+
```
188+
struct _Vector_impl_data
189+
{
190+
    pointer start;//指向vector的头
191+
    pointer finish;//指向vector尾元素后面的位置
192+
    pointer end_of_storage;//指向vector存储空间的末尾
193+
}
194+
```
195+
196+
vector的扩容策略:在vector中添加元素后,如果分配的空间不够用,vector会尝试申请当前空间大小二倍的新空间,然后把旧空间的元素复制过去,释放旧空间,更新指针。
197+
198+
```C++
199+
void reallocate()
200+
{
201+
    auto n=(size()>0)?2*size():1;
202+
    THROW_ERROR_IF(n > max_size(),
203+
    "n can not larger than max_size() in vector<T>::reallocate(n)");
204+
    const auto old_size = size();
205+
    auto tmp = data_allocator::allocate(n);
206+
    mystl::uninitialized_move(start, finish, tmp);
207+
    data_allocator::deallocate(start,end_of_storage-start);
208+
    start = tmp;
209+
    end_of_storage= start + n;
210+
}
211+
212+
```
213+
214+
215+
216+
### array
217+
218+
array 容器的大小是固定的,无法动态的扩展或收缩。
219+
相较于数组而言,array在不损失性能的情况下,泛用性强,并且安全性高。
220+
221+
### deque
222+
223+
deque是双向队列,可以在容器的头和尾插入元素,deque的数据连续存储,可以动态的分配空间。
224+
225+
deque让使用者感觉其拥有线性连续空间,实际其内部的空间是一段一段的缓冲区,由map将它们串联在一起。
226+
227+
deque使用下面的结构体来控制元素的存储:
228+
229+
迭代器:
230+
231+
```C++
232+
  value_pointer cur;    // 指向所在缓冲区的当前元素
233+
  value_pointer first;  // 指向所在缓冲区的头部
234+
  value_pointer last;   // 指向所在缓冲区的尾部
235+
  map_pointer   node;   // 缓冲区所在节点
236+
```
237+
238+
```C++
239+
iterator       begin_;     // 指向第一个节点
240+
iterator       end_;       // 指向最后一个结点
241+
map_pointer    map_;       // 指向一块 map,map 中的每个元素都是一个指针,指向一个缓冲区
242+
size_type      map_size_;  // map 内指针的数目
243+
```
244+
245+
deque是的存储空间扩充:
246+
当我们想deque中添加元素时,如果当前缓冲区没有空间,则会申请一个新的缓冲区,然后将新缓冲区的指针放到map中的相应位置(如果是在尾部添加元素就放到后面,头部添加元素就放在前面)。并且最开始的缓冲区指针放在map的中间,向两边扩充。如果map数组不够用了,就会创建一个新的更大map,然后把旧map中存储的指针拷贝过来,并更新以上元素的值。
247+
248+
### list
249+
250+
list为双向链表,可以快速的在任何位置插入和删除元素。
251+
252+
list的内部时通过双向循环链表实现的。
253+
254+
### forward_list
255+
256+
forward_list为单向链表,只能单向的访问。比list更能节省内存空间。
257+
258+
### set
259+
260+
set内部通过红黑树(RBtree)实现,插入元素的效率高。
261+
262+
### unordered_set
263+
264+
unordered_set通过散列表实现,查找元素的效率高。其采用分离链表法来处理哈希冲突。当散列表中元素的数量超过一定值时,为了保证查找的效率,散列表会采用某种策略进行再散列。
265+

C++ STL.pptx

375 KB
Binary file not shown.

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# MySTL
2+

0 commit comments

Comments
 (0)