STL之vector篇

  N久之前是拿C的数组实现过vector中的一些简单功能,什么深拷贝、增删查找之类的,以为vector的实现也就是这样了,现在想想真是...too young too naive...ORZ

====================我是分割线=============================

vector属于顺序容器,它的底层实现就是基于array,所以它可以支持随机访问,但是它比array更有效率,因为它动态分配的内存空间

动态分配的内存空间:

   每当vector的capacity==size,并且有新element需要加入时,vector会申请一段大小等于2*capacity的连续内存空间,将原来的数据深拷贝到新的内存地址,然后释放掉原来的内存,并添加新的element到内存中。(这一系列内存操作大大影响了vector的存储效率)

      因为,不同的环境下,vector的实现方式有所出入,所以初始化时的capacity大小不一样,但是capacity一定会大于所需的内存大小,预留一定的空间,已减少内存操作。

以下是简单的测试:

环境如下:

g++ 4.8.4

ubuntu 14.04

test1:

  1. #include <iostream>
  2. #include <vector>
  3.  
  4. using namespace std;
  5.  
  6. int main() {
  7. vector<int> v1;
  8. cout << "v1 size = " << v1.size() << endl;
  9. cout << "v1 capacity = " << v1.capacity() << endl;
  10. cout << "v1 max_size = " << v1.max_size() << endl;
  11. vector<char> v2;
  12. cout << "v2 size = " << v2.size() << endl;
  13. cout << "v2 capacity = " << v2.capacity() << endl;
  14. cout << "v2 max_size = " << v2.max_size() << endl;
  15. return ;
  16. }

结果如下:

v1 size = 0
v1 capacity = 0
v1 max_size = 4611686018427387903
v2 size = 0
v2 capacity = 0
v2 max_size = 18446744073709551615

max_size返回vector可以保持的element个数的上限,这个上限与系统的底层实现有关,不一定可以达到(当内存不够时,不能继续分配)

这里可以看出,此时初始化的capacity==0

test2:

  1. #include <iostream>
  2. #include <vector>
  3.  
  4. using namespace std;
  5.  
  6. int main() {
  7. vector<int> v1;
  8. for (int i = ; i < ; ++i)v1.push_back(i);
  9. cout << "v1 size = " << v1.size() << endl;
  10. cout << "v1 capacity = " << v1.capacity() << endl;
  11. cout << "v1 max_size = " << v1.max_size() << endl;
  12. vector<char> v2;
  13. for (int i = ; i < ; ++i)v2.push_back(char(i));
  14. cout << "v2 size = " << v2.size() << endl;
  15. cout << "v2 capacity = " << v2.capacity() << endl;
  16. cout << "v2 max_size = " << v2.max_size() << endl;
  17. return ;
  18. }

结果如下:

v1 size = 1
v1 capacity = 1
v1 max_size = 4611686018427387903
v2 size = 1
v2 capacity = 1
v2 max_size = 18446744073709551615

此时,插入一个元素,capacity==1,size也为1

test3:

  1. #include <iostream>
  2. #include <vector>
  3.  
  4. using namespace std;
  5.  
  6. int main() {
  7. vector<int> v1;
  8. for (int i = ; i < ; ++i)v1.push_back(i);
  9. cout << "v1 size = " << v1.size() << endl;
  10. cout << "v1 capacity = " << v1.capacity() << endl;
  11. cout << "v1 max_size = " << v1.max_size() << endl;
  12. vector<char> v2;
  13. for (int i = ; i < ; ++i)v2.push_back(char(i));
  14. cout << "v2 size = " << v2.size() << endl;
  15. cout << "v2 capacity = " << v2.capacity() << endl;
  16. cout << "v2 max_size = " << v2.max_size() << endl;
  17. return ;
  18. }

结果如下:

v1 size = 2
v1 capacity = 2
v1 max_size = 4611686018427387903
v2 size = 2
v2 capacity = 2
v2 max_size = 18446744073709551615

当插入两个元素时,capacity = 2 * capacity(即为2),然后拷贝之前的数据到新的内存空间,添加新元素,则size==2

test4:

  1. #include <iostream>
  2. #include <vector>
  3.  
  4. using namespace std;
  5.  
  6. int main() {
  7. vector<int> v1;
  8. for (int i = ; i < ; ++i)v1.push_back(i);
  9. cout << "v1 size = " << v1.size() << endl;
  10. cout << "v1 capacity = " << v1.capacity() << endl;
  11. cout << "v1 max_size = " << v1.max_size() << endl;
  12. vector<char> v2;
  13. for (int i = ; i < ; ++i)v2.push_back(char(i));
  14. cout << "v2 size = " << v2.size() << endl;
  15. cout << "v2 capacity = " << v2.capacity() << endl;
  16. cout << "v2 max_size = " << v2.max_size() << endl;
  17. return ;
  18. }

结果如下:

v1 size = 3
v1 capacity = 4
v1 max_size = 4611686018427387903
v2 size = 3
v2 capacity = 4
v2 max_size = 18446744073709551615

又接着添加一个新元素,capacity翻倍(变成4),size增加1,即3

添加新元素的原理get  >   <

===========================第二分割线===================================

以下为删除原理

test5:

  1. #include <iostream>
  2. #include <vector>
  3.  
  4. using namespace std;
  5.  
  6. int main() {
  7. vector<int> v1;
  8. for (int i = ; i < ; ++i)v1.push_back(i);
  9. cout << "v1 size = " << v1.size() << endl;
  10. cout << "v1 capacity = " << v1.capacity() << endl;
  11. cout << "v1 max_size = " << v1.max_size() << endl;
  12. vector<char> v2;
  13. for (int i = ; i < ; ++i)v2.push_back(char(i));
  14. cout << "v2 size = " << v2.size() << endl;
  15. cout << "v2 capacity = " << v2.capacity() << endl;
  16. cout << "v2 max_size = " << v2.max_size() << endl;
  17. return ;
  18. }

结果如下:

v1 size = 129
v1 capacity = 256
v1 max_size = 4611686018427387903
v2 size = 129
v2 capacity = 256
v2 max_size = 18446744073709551615

test6:

  1. #include <iostream>
  2. #include <vector>
  3.  
  4. using namespace std;
  5.  
  6. int main() {
  7. vector<int> v1;
  8. for (int i = ; i < ; ++i)v1.push_back(i);
  9. v1.pop_back();
  10. v1.pop_back();
  11. cout << "v1 size = " << v1.size() << endl;
  12. cout << "v1 capacity = " << v1.capacity() << endl;
  13. cout << "v1 max_size = " << v1.max_size() << endl;
  14. vector<char> v2;
  15. for (int i = ; i < ; ++i)v2.push_back(char(i));
  16. v2.pop_back();
  17. v2.pop_back();
  18. cout << "v2 size = " << v2.size() << endl;
  19. cout << "v2 capacity = " << v2.capacity() << endl;
  20. cout << "v2 max_size = " << v2.max_size() << endl;
  21. return ;
  22. }

结果如下:

v1 size = 127
v1 capacity = 256
v1 max_size = 4611686018427387903
v2 size = 127
v2 capacity = 256
v2 max_size = 18446744073709551615

(⊙v⊙)嗯,看来内存的动态改变并不会随着size的减小的缩减capacity,避免了不必要的内存操作。

C++手册中也有说明,pop_back的操作只是size减1

=============================第三分割线==================================

接着,是各个函数的底层理解

assign() 

  有三种形参形式(iterator begin,iterator end)初始化为迭代器指向的容器之间的内容;(n, value)初始化N个值为value的元素;(initializer_list<value_type> il)深拷贝

back()

  返回vector中最后一个值,当vector为空时,调用该函数会报错

front()

  返回vector中第一个值,当vector为空时,调用该函数会报错

begin()

  返回指向第一个element的迭代器

end()

  返回指向past-the-end element的迭代器,past-the-end element是理论上应该跟在最后一个element后面的位置,但是那个位置上并没有存放element

cbegin()

  返回一个首个元素的const_iterator迭代器,用该迭代器访问元素是是不可以用来改变元素本身值的(即便元素本身并非const类型)

cend()

  返回一个past-the-last element的const_iterator迭代器

crbegin()

  r表示逆序,c表示const,此处返回vector中逆序第一个element的const_iterator

crend()

  此处返回vector中第一个element的const_iterator,功能与cbegin()相同

rbegin()

  返回逆序第一个element的迭代器,即为指向end()的前一个位置的迭代器

rend()

  返回逆序的最后一个element的迭代器,即指向第一个element

capacity()

  返回vector容器已开辟的内存可存放element的个数

size()

  返回当前vector中已有的element个数,size <= capacity

max_size()

  返回一个理论上允许的capacity上限值,但不一定能达到

data()

  返回一个指向当前容器内存起始地址的指针,由于vector的内存分配是连续的,所以可以直接用指针offset来为容器中的element赋值

  std::vector<int> myvector (5);

  int* p = myvector.data();

  *p = 10;

  ++p;

  *p = 20;

  1. p[2] = 100;

emplace()

关于emplace和insert的区别,如下:

(emplace会调用类的构造函数,代码搬运自:http://stackoverflow.com/questions/14788261/c-stdvector-emplace-vs-insert)

  1. struct Foo
  2. {
  3. Foo(int n, double x);
  4. };
  5.  
  6. std::vector<Foo> v;
  7. v.emplace(someIterator, , 3.1416);
  8. v.insert(someIterator, Foo(, 3.1416));

emplace_back()

  调用构造函数,然后把element加到末尾

insert()

  可以把element插入到迭代器指定的element之前的位置。

  由于底层实现时array,除了在末尾插入element,在其他的位置插入,都需要将指定插入位置后面的element移位,这将导致效率低下

  如果插入之后size>capacity,则参考push_back的重新申请内存空间

erase()

  删除指定区间或者位置的element,同样,除了删除末尾的element,删除其他位置的element都需要把后面的element往前移动,也是导致效率低的原因

clear()

  把所有element都移除,size=0,此时capacity不一定为0(不一定会有释放内存的操作)//正确的释放内存姿势——swap()

empty()

  size >= 0, 返回false;否则返回true

get_allocator()

  返回该容器的allocator

operator=

  拷贝,STL中的拷贝都是深拷贝

operator[]

  访问节点

push_back()

  在末尾增加一个element,当size超出时,capacity翻倍(具体看此博文开头),size++

pop_back()

  移除末尾一个element, size--

reserve()

  v.reserve(n);表示此时V的capacity至少要大于等于300,若capacity<300,则重新申请内存;反之则不用做其他操作;

  

  1. #include <iostream>
  2. #include <vector>
  3.  
  4. using namespace std;
  5.  
  6. int main() {
  7. vector<int> v1;
  8. for (int i = ; i < ; ++i)v1.push_back(i);
  9. v1.pop_back();
  10. v1.pop_back();
  11. cout << "v1 size = " << v1.size() << endl;
  12. cout << "v1 capacity = " << v1.capacity() << endl;
  13. cout << "v1 max_size = " << v1.max_size() << endl;
  14. vector<char> v2;
  15. for (int i = ; i < ; ++i)v2.push_back(char(i));
  16. v2.reserve();
  17. cout << "v2 size = " << v2.size() << endl;
  18. cout << "v2 capacity = " << v2.capacity() << endl;
  19. cout << "v2 max_size = " << v2.max_size() << endl;
  20. return ;
  21. }

结果为:

v1 size = 127
v1 capacity = 256
v1 max_size = 4611686018427387903
v2 size = 129
v2 capacity = 300
v2 max_size = 18446744073709551615

resize()

  v.resize(n)将会把v中的size调整为n大小,若n > size,则用0补足element;若n < size,则取容器中的前n个element,其与元素移除;

  v.resize(n,m)将会把v中的size调整为n大小,若n > size,则用m补足element

  

  1. #include <iostream>
  2. #include <vector>
  3.  
  4. using namespace std;
  5.  
  6. int main() {
  7. vector<int> v1;
  8. for (int i = ; i < ; ++i)v1.push_back(i);
  9. for (int i = ; i < v1.size(); i ++)cout << v1[i] << " ";
  10. cout << endl;
  11. cout << "v1 size = " << v1.size() << endl;
  12. cout << "v1 capacity = " << v1.capacity() << endl;
  13. cout << "v1 max_size = " << v1.max_size() << endl;
  14.  
  15. v1.resize();
  16. for (int i = ; i < v1.size(); i ++)cout << v1[i] << " ";
  17. cout << endl;
  18. cout << "v1 size = " << v1.size() << endl;
  19. cout << "v1 capacity = " << v1.capacity() << endl;
  20. cout << "v1 max_size = " << v1.max_size() << endl;
  21.  
  22. v1.resize(, );
  23. for (int i = ; i < v1.size(); i ++)cout << v1[i] << " ";
  24. cout << endl;
  25. cout << "v1 size = " << v1.size() << endl;
  26. cout << "v1 capacity = " << v1.capacity() << endl;
  27. cout << "v1 max_size = " << v1.max_size() << endl;
  28.  
  29. v1.resize();
  30. for (int i = ; i < v1.size(); i ++)cout << v1[i] << " ";
  31. cout << endl;
  32. cout << "v1 size = " << v1.size() << endl;
  33. cout << "v1 capacity = " << v1.capacity() << endl;
  34. cout << "v1 max_size = " << v1.max_size() << endl;
  35. return ;
  36. }

结果如下:

0 1 2 3 4 5 6 7 8 9
v1 size = 10
v1 capacity = 16
v1 max_size = 4611686018427387903
0 1 2 3 4 5 6
v1 size = 7
v1 capacity = 16
v1 max_size = 4611686018427387903
0 1 2 3 4 5 6 200 200 200 200 200 200 200 200 200 200 200 200 200
v1 size = 20
v1 capacity = 20
v1 max_size = 4611686018427387903
0 1 2 3 4 5 6 200 200 200 200 200 200 200 200 200 200 200 200 200 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
v1 size = 50
v1 capacity = 50
v1 max_size = 4611686018427387903

shrink_to_fit()

  一般来说capacity满足,capacity>=size;v.shrink_to_fit()操作可以使得,capacity==size,这也是释放内存的操作之一!!!

  

  1. #include <iostream>
  2. #include <vector>
  3.  
  4. using namespace std;
  5.  
  6. int main() {
  7. vector<int> v1;
  8. for (int i = ; i < ; ++i)v1.push_back(i);
  9. cout << "v1 size = " << v1.size() << endl;
  10. cout << "v1 capacity = " << v1.capacity() << endl;
  11. cout << "v1 max_size = " << v1.max_size() << endl;
  12.  
  13. v1.resize();
  14. cout << "v1 size = " << v1.size() << endl;
  15. cout << "v1 capacity = " << v1.capacity() << endl;
  16. cout << "v1 max_size = " << v1.max_size() << endl;
  17.  
  18. v1.shrink_to_fit();
  19. cout << "v1 size = " << v1.size() << endl;
  20. cout << "v1 capacity = " << v1.capacity() << endl;
  21. cout << "v1 max_size = " << v1.max_size() << endl;
  22.  
  23. return ;
  24. }

结果如下:

v1 size = 10
v1 capacity = 16
v1 max_size = 4611686018427387903
v1 size = 7
v1 capacity = 16
v1 max_size = 4611686018427387903
v1 size = 7
v1 capacity = 7
v1 max_size = 4611686018427387903

swap()

  v.swap(v2)的操作可以将v,和v2中的element交换

  1. #include <iostream>
  2. #include <vector>
  3.  
  4. using namespace std;
  5.  
  6. int main() {
  7. vector<int> v1;
  8. for (int i = ; i < ; ++i)v1.push_back(i);
  9. cout << "v1 size = " << v1.size() << endl;
  10. cout << "v1 capacity = " << v1.capacity() << endl;
  11. cout << "v1 max_size = " << v1.max_size() << endl;
  12.  
  13. vector<int> v2;
  14. for (int i = ; i < ; ++i)v2.push_back(i);
  15. cout << "v2 size = " << v2.size() << endl;
  16. cout << "v2 capacity = " << v2.capacity() << endl;
  17. cout << "v2 max_size = " << v2.max_size() << endl;
  18.  
  19. v1.swap(v2);
  20. cout << "v1 size = " << v1.size() << endl;
  21. cout << "v1 capacity = " << v1.capacity() << endl;
  22. cout << "v1 max_size = " << v1.max_size() << endl;
  23. cout << "v2 size = " << v2.size() << endl;
  24. cout << "v2 capacity = " << v2.capacity() << endl;
  25. cout << "v2 max_size = " << v2.max_size() << endl;
  26.  
  27. return ;
  28. }

结果如下:

v1 size = 10
v1 capacity = 16
v1 max_size = 4611686018427387903
v2 size = 20
v2 capacity = 32
v2 max_size = 4611686018427387903
v1 size = 20
v1 capacity = 32
v1 max_size = 4611686018427387903
v2 size = 10
v2 capacity = 16
v2 max_size = 4611686018427387903

小结:

vector是不会自动释放内存的,但是如果size的极大值很大的话会造成capacity很大,浪费内存。

所以以下有几种方法可以释放vector的内存:

  ①shrink_to_fit

  1. #include <iostream>
  2. #include <vector>
  3.  
  4. using namespace std;
  5.  
  6. int main() {
  7. vector<int> v1;
  8. for (int i = ; i < ; ++i)v1.push_back(i);
  9. cout << "v1 size = " << v1.size() << endl;
  10. cout << "v1 capacity = " << v1.capacity() << endl;
  11.  
  12. v1.clear();
  13. cout << "v1 size = " << v1.size() << endl;
  14. cout << "v1 capacity = " << v1.capacity() << endl;
  15.  
  16. v1.shrink_to_fit();
  17. cout << "v1 size = " << v1.size() << endl;
  18. cout << "v1 capacity = " << v1.capacity() << endl;
  19.  
  20. return ;
  21. }

结果:

v1 size = 20

v1 capacity = 32

v1 size = 0
v1 capacity = 32
v1 size = 0
v1 capacity = 0

  

  ②swap

  

  1. #include <iostream>
  2. #include <vector>
  3.  
  4. using namespace std;
  5.  
  6. int main() {
  7. vector<int> v1;
  8. for (int i = ; i < ; ++i)v1.push_back(i);
  9. cout << "v1 size = " << v1.size() << endl;
  10. cout << "v1 capacity = " << v1.capacity() << endl;
  11.  
  12. vector<int>().swap(v1);
  13. cout << "v1 size = " << v1.size() << endl;
  14. cout << "v1 capacity = " << v1.capacity() << endl;
  15.  
  16. return ;
  17. }

结果如下:

v1 size = 20
v1 capacity = 32
v1 size = 0
v1 capacity = 0

 

    ③指针释放

    

  1. #include <iostream>
  2. #include <vector>
  3.  
  4. using namespace std;
  5.  
  6. int main() {
  7. vector<int> v;
  8. vector<int>* v1 = &v;
  9. for (int i = ; i < ; ++i)v1->push_back(i);
  10. cout << "v size = " << v.size() << endl;
  11. cout << "v capacity = " << v.capacity() << endl;
  12.  
  13. delete v1;
  14. return ;
  15. }

========================我是第四分割线============================

C++11的标准中,vector新增加的成员函数:

crbegin

crend

cbegin

cend

emplace

emplace_back

data

shrink_to_fit

========================我是第五分割线============================

最后简单说说,高效索引之bitset和vector<bool>

bitset  可以进行位操作,但是大小固定

vector<bool>   属于vector的一种特殊形式,用bool类型的allocator构造,但是在实现的时候优化了,所以它的element类型并不是bool,而是bit

【C++】朝花夕拾——STL vector的更多相关文章

  1. C++ STL vector容器学习

    STL(Standard Template Library)标准模板库是C++最重要的组成部分,它提供了一组表示容器.迭代器.函数对象和算法的模板.其中容器是存储类型相同的数据的结构(如vector, ...

  2. STL vector

    STL vector vector是线性容器,它的元素严格的按照线性序列排序,和动态数组很相似,和数组一样,它的元素存储在一块连续的存储空间中,这也意味着我们不仅可以使用迭代器(iterator)访问 ...

  3. STL vector用法介绍

    STL vector用法介绍 介绍 这篇文章的目的是为了介绍std::vector,如何恰当地使用它们的成员函数等操作.本文中还讨论了条件函数和函数指针在迭代算法中使用,如在remove_if()和f ...

  4. STL vector+sort排序和multiset/multimap排序比较

    由 www.169it.com 搜集整理 在C++的STL库中,要实现排序可以通过将所有元素保存到vector中,然后通过sort算法来排序,也可以通过multimap实现在插入元素的时候进行排序.在 ...

  5. STL vector 用法介绍

    介绍 这篇文章的目的是为了介绍std::vector,如何恰当地使用它们的成员函数等操作.本文中还讨论了条件函数和函数指针在迭代算法中使用,如在remove_if()和for_each()中的使用.通 ...

  6. STL vector使用方法介绍

    介绍 这篇文章的目的是为了介绍std::vector,怎样恰当地使用它们的成员函数等操作.本文中还讨论了条件函数和函数指针在迭代算法中使用,如在remove_if()和for_each()中的使用.通 ...

  7. stl——vector详解

    stl——vector详解 stl——vector是应用最广泛的一种容器,类似于array,都将数据存储于连续空间中,支持随机访问.相对于array,vector对空间应用十分方便.高效,迭代器使ve ...

  8. C++STL vector详解(杂谈)

    介绍 这篇文章的目的是为了介绍std::vector,如何恰当地使用它们的成员函数等操作.本文中还讨论了条件函数和函数指针在迭代算法中使用,如在remove_if()和for_each()中的使用.通 ...

  9. C++ stl vector介绍

    转自: STL vector用法介绍 介绍 这篇文章的目的是为了介绍std::vector,如何恰当地使用它们的成员函数等操作.本文中还讨论了条件函数和函数指针在迭代算法中使用,如在remove_if ...

随机推荐

  1. jsonp突破同源策略,实现跨域訪问请求

    版权声明:本文为博主原创文章,未经博主同意不得转载.如需转载请声明:[转自 http://blog.csdn.net/xiaoxian8023 ] https://blog.csdn.net/xiao ...

  2. solr 7.2.1 单机及伪集群启动

    1.solr的下载: 下载地址:solr官网:http://lucene.apache.org/solr进入官网点击download或者点击链接https://lucene.apache.org/so ...

  3. bacth参数说明 cmd parameter

    http://www.robvanderwoude.com/parameters.php Windows NT 4 introduced a set of new features for comma ...

  4. 贪吃蛇 javaScript 谷歌浏览器浏览

    1.代码:<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3 ...

  5. windows 操作系统问题的解决

    浏览器之间具有较大的差异: 如果某问题只存在于某浏览器,而其他浏览器不存在此问题,则说明,问题出在该浏览器上: 或者是缓存已满:⇒ 清除缓存: 或者浏览器的兼容性问题: 1. error 1327. ...

  6. 【POJ 1947】 Rebuilding Roads

    [题目链接] 点击打开链接 [算法] f[i][j]表示以i为根的子树中,最少删多少条边可以组成j个节点的子树 树上背包,即可 [代码] #include <algorithm> #inc ...

  7. 【OpenFOAM】——OpenFOAM入门算例学习

    1  明确目标——为啥费老大劲儿学习OpenFOAM 学习OpenFOAM主要出于课题需要,希望实现以下几个目标: l  [ ]学会用SnappyHexMesh生成高质量网格: l  [ ]学习使用O ...

  8. tar 报错gzip: stdin: not in gzip format(转载)

    转自:http://blog.sina.com.cn/s/blog_6f2274fb0100z026.html 今天在linux下 用tar -zxf xxx.tar.bz2 然后就报这个错. gzi ...

  9. jsp请求转发小例子(转载)

    在服务器端对客户端请求时行转发对其它的对象,如果jsp网页或Servlet 用三个 jsp网页来演示转发: forword1.jsp, 用来提交表单, 将表单内容提交给 forwrod2.jsp,  ...

  10. Codeforces Round #386 (Div. 2)G. New Roads [构造][树]

    题目链接:G. New Roads 题意:给出n个结点,t层深度,每层有a[i]个结点,总共有k个叶子结点,构造一棵树. 分析: 考虑一颗树,如果满足每层深度上有a[i]结点,最多能有多少叶子结点 那 ...