文章目录
empty()和size()都可以判断容器是否为空,谁更好?
建议使用 empty() 成员方法。理由很简单,无论是哪种容器,只要其模板类中提供了 empty() 成员方法,使用此方法都可以保证在 O(1) 时间复杂度内完成对“容器是否为空”的判断;但对于 list 容器来说,使用 size() 成员方法判断“容器是否为空”,可能要消耗 O(n) 的时间复杂度。
此处参考
array 为何比 普通数组 安全
普通数组没有做任何边界检查,所以即便使用越界的索引值去访问或存储元素,也不会被检测到
例如:
int test2[10] = { 1,2,3,4,5 };
test2[4] = 2.0 * test2[111];
std::cout << test2[4] << std::endl;
注意:array 这样使用也不会被检测到
std::array<int, 10> test{ 1,2,3,4,5 };
test[4] = 2.0 * test[111];
std::cout << test[4] << std::endl;
为了能够有效地避免越界访问的情况,可以使用 array 容器提供的 at() 成员函数,例如 :
std::array<int, 10> test{ 1,2,3,4,5 };
test.at(4) = 2.0 * test.at(111);
std::cout << test[4] << std::endl;
vector容器的 容量(capacity)和 大小(size)的区别
vector 容器的容量(用 capacity 表示),指的是在不分配更多内存的情况下,容器可以保存的最多元素个数;而 vector 容器的大小(用 size 表示),指的是它实际所包含的元素个数。
注意: 当 vector 容器的大小和容量相等时,如果再向其添加(或者插入)一个元素,vector 往往会申请多个存储空间,而不仅仅只申请 1 个,并且容器会重新生成。
例:
int main() {
std::vector<int>test{ 1,2,3,4,5 };
std::cout << "test 容量是:" << test.capacity() << std::endl;
std::cout << "test 大小是:" << test.size() << std::endl;
std::cout << "test首地址:" <<test.data() << std::endl;
test.push_back(6);
std::cout << "test 容量是(2):" << test.capacity() << std::endl;
std::cout << "test 大小是(2):" << test.size() << std::endl;
std::cout << "test首地址:" << test.data() << std::endl;
test.push_back(7);
std::cout << "test 容量是(2):" << test.capacity() << std::endl;
std::cout << "test 大小是(2):" << test.size() << std::endl;
std::cout << "test首地址:" << test.data() << std::endl;
}
结果:
test 容量是:5
test 大小是:5
test首地址:00000237D6E200E0
test 容量是(2):7
test 大小是(2):6
test首地址:00000237D6E1D320
test 容量是(2):7
test 大小是(2):7
test首地址:00000237D6E1D320
可见当容器的大小超过容器的容量的时候,容器的首地址改变了,说明容器重建了
注意:当 vector 容器的大小和容量相等时,向其添加一个元素时会使得首地址发生改变。(经常有人因此发生bug,需要注意)
vector内部的扩容步骤:
- 弃用现有的内存空间,重新申请更大的内存空间;
- 将旧内存空间中的数据,按原有顺序移动到新的内存空间中;
- 将旧的内存空间释放。
vector添加元素push_back()和emplace_back()的区别
emplace_back() 和 push_back() 的区别,就在于底层实现的机制不同。push_back() 向容器尾部添加元素时,首先会创建这个元素,然后再将这个元素拷贝或者移动到容器中(如果是拷贝的话,事后会自行销毁先前创建的这个元素);而 emplace_back() 在实现时,则是直接在容器尾部创建这个元素,省去了拷贝或移动元素的过程。
简而言之:emplace_back()是c++11 新添加的,效率要比push_back()高
vector插入元素insert()和emplace()的区别
语法格式 | 用法说明 |
---|---|
iterator insert(pos,elem) | 在迭代器 pos 指定的位置之前插入一个新元素elem,并返回表示新插入元素位置的迭代器。 |
iterator insert(pos,n,elem) | 在迭代器 pos 指定的位置之前插入 n 个元素 elem,并返回表示第一个新插入元素位置的迭代器。 |
iterator insert(pos,first,last) | 在迭代器 pos 指定的位置之前,插入其他容器(不仅限于vector)中位于 [first,last) 区域的所有元素,并返回表示第一个新插入元素位置的迭代器。 |
iterator insert(pos,initlist) | 在迭代器 pos 指定的位置之前,插入初始化列表(用大括号{}括起来的多个元素,中间有逗号隔开)中所有的元素,并返回表示第一个新插入元素位置的迭代器。 |
iterator emplace (pos, elem) | 在迭代器 pos 指定的位置之前插入一个新元素elem,并返回表示新插入元素位置的迭代器。 |
可见:insert() 的功能要比 emplace()多。单比较插入一个元素,emplace()效率要比insert()要高,原因同上一条。
vecter容器使用remove()需要注意:
注意: remove()不是vector的成员函数,该函数定义在 头文件中
通过remove()函数删除 vector容器中的多个指定元素,该容器的大小和容量都没有改变,其剩余位置还保留了之前存储的元素,还需要使用 erase() 成员函数删掉这些无用的元素。
如图:
例子:
int main() {
std::vector<int>test{ 9,9,9,1,2,3,4,5,6,7,8,9 };
std::cout << "size:"<< test.size() << std::endl;
std::cout << "capacity:" << test.capacity() << std::endl;
for (auto i : test) {
printf(" %d", i);
}
printf("\n");
auto iter = std::remove(test.begin(), test.end(), 9);
for (auto i : test) {
printf(" %d", i);
}
printf("\n");
std::cout << "size:" << test.size() << std::endl;
std::cout << "capacity:" << test.capacity() << std::endl;
test.erase(iter, test.end());
for (auto i : test) {
printf(" %d", i);
}
printf("\n");
std::cout << "size:" << test.size() << std::endl;
std::cout << "capacity:" << test.capacity() << std::endl;
}
结果:
size:12
capacity:12
9 9 9 1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 6 7 8 9
size:12
capacity:12
1 2 3 4 5 6 7 8
size:8
capacity:12
为何要避免使用vector
这是个c++ 的历史遗留问题,在早先vector每个元素是存在一个bit中而不是byte。
且vector 不完全满足 C++ 标准中对容器的要求,
所以vector就不是一个容器,尽量避免在实际场景中使用它!
在需要用到的时候用 deque 代替
deque容器为什么没有提供data()成员函数 ( 为何不要使用指针去访问deque容器中指定位置处的元素 )
和vector不同,deque的存储空间不一定是连续的,通常他是有多个连续的空间组成的。因此尝试使用指针去访问 deque 容器中指定位置处的元素,是非常危险的
deque的存储方式如下图所示:
forward_list没有size()成员函数,如何获取元素个数
可以使用头文件 中的 distance() 函数
#include <iostream>
#include <forward_list>
#include <iterator>
int main()
{
std::forward_list<int> test{1,2,3,4,5,6,7,8,9,10};
int size = std::distance(test.begin(), test.end());
int size2 = std::distance(std::begin(test), std::end(test));
std::cout << "size:" << size << std::endl;
std::cout << "size2:" << size2 << std::endl;
}
size:10
size2:10