Vector容器

C++中vector使用详细说明  2013-07-03 11:20:48

分类: C/C++

1. 在C++中的详细说明
vector是C++标准模板库中的部分内容,它是一个多功能的,能够操作多种数据结构和算法的模板类和函数库。
vector之所以被认为是一个容器,是因为它能够像容器一样存放各种类型的对象,
简单地说,vector是一个能够存放任意类型的动态数组,能够增加和压缩数据。


2. 使用vector,
必须在你的头文件中包含下面的代码:

  #include <vector>
vector属于std命名域的,因此需要通过命名限定,如下完成你的代码:
  using std::vector;
  vector<int> vInts;   
或者连在一起,使用全名:  
    std::vector<int> vInts;   
建议使用全局的命名域方式:
    using namespace std;

3. 初始化   
vector <Elem>                 // 创建一个空的vector。
vector <Elem> c1(c2)          // 复制一个vector
vector <Elem> c(n)            // 创建一个vector,含有n个数据,数据均已缺省构造产生
vector <Elem> c(n, elem)      // 创建一个含有n个elem拷贝的vector
vector <Elem> c(beg,end)      // 创建一个含有n个elem拷贝的vector

4. 析构函数
c.~vector <Elem>()           // 销毁所有数据,释放内存

5. 成员函数
c.assign(beg,end)c.assign(n,elem)
  将[beg; end)区间中的数据赋值给c。将n个elem的拷贝赋值给c。
c[i] 传回c中位置为i的元素
c.at(idx) 传回索引idx所指的数据,如果idx越界,抛出out_of_range。而c[i]不会。
c.begin()     // 传回迭代器中的第一个数据地址。
c.end()       //指向迭代器中末端元素的下一个,指向一个不存在元素。
c.size()           // 返回容器中实际数据的个数。
c.capacity()  // 返回容器中数据个数。
c.clear()     // 移除容器中所有数据。
c.empty()     // 判断容器是否为空。
c.erase(pos)  // 删除pos位置的数据,传回下一个数据的位置。
c.erase(beg,end)  //删除[beg,end)区间的数据,传回下一个数据的位置。
c.front()     // 传回第一个数据。
c.back()      //返回容器最后一个数据,不检查这个数据是否存在。
get_allocator // 使用构造函数返回一个拷贝。
c.insert(pos,elem)    // 在pos位置插入一个elem拷贝,传回新数据位置。
c.insert(pos,n,elem)  // 在pos位置插入n个elem数据。无返回值。
c.insert(pos,beg,end) // 在pos位置插入在[beg,end)区间的数据。无返回值。
  
c.max_size()       // 返回容器中最大数据的数量。
c.pop_back()       // 删除最后一个数据。
c.push_back(elem)  // 在尾部加入一个数据。

c.rbegin()         // 传回一个逆向队列的第一个数据的地址。ji传回迭代器中的最后一个数据地址
c.rend()           // 传回一个逆向队列的最后一个数据的下一个位置
c.resize(num)      // 重新指定队列的长度。
c.reserve()        // 保留适当的容量。

c1.swap(c2)
swap(c1,c2)        // 将c1和c2元素互换。同上操作。

operator[]         // 返回容器中指定位置的一个引用。



#include<algorithm>中的泛函算法 
搜索算法:find() 、search() 、count() 、find_if() 、search_if() 、count_if()  分类排序:sort() 、merge()  删除算法:unique() 、remove()  
生成和变异:generate() 、fill() 、transformation() 、copy()  关系算法:equal() 、min() 、max()  
sort(v1.begin(),vi.begin()+v1.size/2); 对v1的前半段元素排序 
list<char>::iterator pMiddle =find(cList.begin(),cList.end(),'A');找到则返回被查内容第一次出现处指针,否则返回end()。 
vector< typeName >::size_type x  vector< typeName >类型的计数,可用于循环如同for(int i) 
初学C++的程序员可能会认为vector的下标操作可以添加元素,其实不然: vector<int> ivec;   // empty vector 
for (vector<int>::size_type ix = 0; ix != 10; ++ix)      ivec[ix] = ix; // disaster: ivec has no elements 
上述程序试图在ivec中插入10个新元素,元素值依次为0到9的整数。但是,这里ivec是空的vector对象,而且下标只能用于获取已存在的元素。 
这个循环的正确写法应该是: 
for (vector<int>::size_type ix = 0; ix != 10; ++ix) 
     ivec.push_back(ix); // ok: adds new element with value ix 
警告:必须是已存在的元素才能用下标操作符进行索引。通过下标操作进行赋值时,不会添加任何元素。仅能对确知已存在的元素进行下标操作   
    
内存管理与效率 
      1.使用reserve()函数提前设定容量大小,避免多次容量扩充操作导致效率低下。 
        关于STL容器,最令人称赞的特性之一就是是只要不超过它们的最大大小,它们就可以自动增长到足以容纳你放进去的数据。(要知道这个最大值,只要调用名叫max_size的成员函数。)对于vector和string,如果需要更多空间,就以类似realloc的思想来增长大小。vector容器支持随机访问,因此为了提高效率,它内部使用动态数组的方式实现的。在通过 reserve() 来申请特定大小的时候总是按指数边界来增大其内部缓冲区。当进行insert或push_back等增加元素的操作时,如果此时动态数组的内存不够用,就要动态的重新分配当前大小的1.5~2倍的新内存区,再把原数组的内容复制过去。所以,在一般情况下,其访问速度同一般数组,只有在重新分配发生时,其性能才会下降。正如上面的代码告诉你的那样。而进行pop_back操作时,capacity并不会因为vector容器里的元素减少而有所下降,还会维持操作之前的大小。对于vector容器来说,如果有大量的数据需要进行push_back,应当使用reserve()函数提前设定其容量大小,否则会出现许多次容量扩充操作,导致效率低下。 
      reserve成员函数允许你最小化必须进行的重新分配的次数,因而可以避免真分配的开销和迭代器/指针/引用失效。但在我解释reserve为什么可以那么做之前,让我简要介绍有时候令人困惑的四个相关成员函数。在标准容器中,只有vector和string提供了所有这些函数。 
(1) size()告诉你容器中有多少元素。它没有告诉你容器为它容纳的元素分配了多少内存。  
(2) capacity()告诉你容器在它已经分配的内存中可以容纳多少元素。那是容器在那块内存中总共可以容纳多少元素,而不是还可以容纳多少元素。如果你想知道一个vector或string中有多少没有被占用的内存,你必须从capacity()中减去size()。如果size和capacity返回同样的值,容器中就没有剩余空间了,而下一次插入(通过insert或push_back等)会引发上面的重新分配步骤。  
(3) resize(Container::size_type n)强制把容器改为容纳n个元素。调用resize之后,size将会返回n。如果n小于当前大小,容器尾部的元素会被销毁。如果n大于当前大小,新默认构造的元素会添加到容器尾部。如果n大于当前容量,在元素加入之前会发生重新分配。  
(4) reserve(Container::size_type n)强制容器把它的容量改为至少n,提供的n不小于当前大小。这一般强迫进行一次重新分配,因为容量需要增加。(如果n小于当前容量,vector忽略它,这个调用什么都不做,string可能把它的容量减少为size()和n中大的数,但string的大小没有改变。在我的经验中,使用reserve来从一个string中修整多余容量一般不如使用“交换技巧”,那是条款17的主题。)      这个简介表示了只要有元素需要插入而且容器的容量不足时就会发生重新分配(包括它们维护的原始内存分配和回收,对象的拷贝和析构和迭代器、指针和引用的失效)。所以,避免重新分配的关键是使用reserve尽快把容器的容量设置为足够大,最好在容器被构造之后立刻进行。 
例如,假定你想建立一个容纳1-1000值的vector<int>。没有使用reserve,你可以像这样来做: 
vector<int> v; 
for (int i = 1; i <= 1000; ++i) 
v.push_back(i);
 在大多数STL实现中,这段代码在循环过程中将会导致2到10次重新分配。(10这个数没什么奇怪的。记住vector在重新分配发生时一般把容量翻倍,而1000约等于210。) 
把代码改为使用reserve,我们得到这个: 
vector<int> v; v.reserve(1000); 
for (int i = 1; i <= 1000; ++i) 
v.push_back(i); 
这在循环中不会发生重新分配。 
在大小和容量之间的关系让我们可以预言什么时候插入将引起vector或string执行重新分配,而且,可以预言什么时候插入会使指向容器中的迭代器、指针和引用失效。例如,给出这段代码, 
string s; ... 
if (s.size() < s.capacity()) 
{ s.push_back('x'); } 
push_back的调用不会使指向这个string中的迭代器、指针或引用失效,因为string的容量保证大于它的大小。如果不是执行push_back,代码在string的任意位置进行一个insert,我们仍然可以保证在插入期间没有发生重新分配,但是,与伴随string插入时迭代器失效的一般规则一致,所有从插入位置到string结尾的迭代器/指针/引用将失效。 
回到本条款的主旨,通常有两情况使用reserve来避免不必要的重新分配。第一个可用的情况是当你确切或者大约知道有多少元素将最后出现在容器中。那样的话,就像上面的vector代码,你只是提前reserve适当数量的空间。第二种情况是保留你可能需要的最大的空间,然后,一旦你添加完全部数据,修整掉任何多余的容量。
6. 用法示例:
6.1. 创建一个vector
vector容器提供了多种创建方法,下面介绍几种常用的。
创建一个Widget类型的空的vector对象:
  vector<Widget> vWidgets;
  
创建一个包含500个Widget类型数据的vector:
  vector<Widget> vWidgets(500);
  
创建一个包含500个Widget类型数据的vector,并且都初始化为0:
  vector<Widget> vWidgets(500, Widget(0));
  
创建一个Widget的拷贝:
  vector<Widget> vWidgetsFromAnother(vWidgets);
  
向vector添加一个数据
  vector添加数据的缺省方法是push_back()。
    push_back()函数表示将数据添加到vector的尾部,并按需要来分配内存。


例如:向vector<Widget>中添加10个数据,需要如下编写代码:
  for(int i= 0;i<10; i++) {
    vWidgets.push_back(Widget(i));
  }


6.2 获取vector中指定位置的数据
  vector里面的数据是动态分配的,使用push_back()的一系列分配空间常常决定于文件或一些数据源。
    如果想知道vector存放了多少数据,可以使用empty()。
    获取vector的大小,可以使用size()。


例如,如果想获取一个vector v的大小,但不知道它是否为空,或者已经包含了数据,如果为空想设置为-1,
你可以使用下面的代码实现:
  int nSize = v.empty() ? -1 : static_cast<int>(v.size());
  
6.3 访问vector中的数据
使用两种方法来访问vector。

1、 vector::at()
2、 vector::operator[]
  operator[]主要是为了与C语言进行兼容。它可以像C语言数组一样操作。
    但at()是我们的首选,因为at()进行了边界检查,如果访问超过了vector的范围,将抛出一个例外。
    由于operator[]容易造成一些错误,所有我们很少用它,下面进行验证一下:
  
分析下面的代码:
  vector<int> v;
  v.reserve(10);
  
    for(int i=0; i<7; i++) {
    v.push_back(i);
  }
  
    try {int iVal1 = v[7];
    // not bounds checked - will not throw
    int iVal2 = v.at(7);
    // bounds checked - will throw if out of range
  } 
    
    catch(const exception& e) {
    cout << e.what();
  }
  
6.3 删除vector中的数据
vector能够非常容易地添加数据,也能很方便地取出数据,
同样vector提供了erase(),pop_back(),clear()来删除数据,
当删除数据时,应该知道要删除尾部的数据,或者是删除所有数据,还是个别的数据。

Remove_if()算法 如果要使用remove_if(),需要在头文件中包含如下代码::
  #include <algorithm>

Remove_if()有三个参数:
  1、 iterator _First:指向第一个数据的迭代指针。
  2、 iterator _Last:指向最后一个数据的迭代指针。
  3、 predicate _Pred:一个可以对迭代操作的条件函数。
  
6.4 条件函数
条件函数是一个按照用户定义的条件返回是或否的结果,是最基本的函数指针,或是一个函数对象。
这个函数对象需要支持所有的函数调用操作,重载operator()()操作。
remove_if()是通过unary_function继承下来的,允许传递数据作为条件。


例如,假如想从一个vector<CString>中删除匹配的数据,如果字串中包含了一个值,从这个值开始,从这个值结束。
首先应该建立一个数据结构来包含这些数据,类似代码如下:
#include <functional>
enum findmodes {
  FM_INVALID = 0,
  FM_IS,
 FM_STARTSWITH,
 FM_ENDSWITH,
 FM_CONTAINS
};

typedef struct tagFindStr {
 UINT iMode;
 CString szMatchStr;
} FindStr;


typedef FindStr* LPFINDSTR;
  
然后处理条件判断:
class FindMatchingString : public std::unary_function<CString, bool> {
public:
 FindMatchingString(const LPFINDSTR lpFS) :
 m_lpFS(lpFS) {}
 bool operator()(CString& szStringToCompare) const {
  bool retVal = false;
  
    switch (m_lpFS->iMode) {
  case FM_IS: {
    retVal = (szStringToCompare == m_lpFDD->szMatchStr);
    break;
  }
  case FM_STARTSWITH: {
    retVal = (szStringToCompare.Left(m_lpFDD->szMatchStr.GetLength())
      == m_lpFDD->szWindowTitle);
    break;
  }
  case FM_ENDSWITH: {
    retVal = (szStringToCompare.Right(m_lpFDD->szMatchStr.GetLength())
      == m_lpFDD->szMatchStr);
  break;
  }
  case FM_CONTAINS: {
    retVal = (szStringToCompare.Find(m_lpFDD->szMatchStr) != -1);
    break;
  }
   }
   return retVal;
  }
private:
 LPFINDSTR m_lpFS;
};

通过这个操作你可以从vector中有效地删除数据:
    FindStr fs;
  fs.iMode = FM_CONTAINS;
  fs.szMatchStr = szRemove;
  vs.erase(std::remove_if(vs.begin(), vs.end(), FindMatchingString(&fs)), vs.end());
  
Remove(),remove_if()等所有的移出操作都是建立在一个迭代范围上的,不能操作容器中的数据。
所以在使用remove_if(),实际上操作的时容器里数据的上面的。


看到remove_if()实际上是根据条件对迭代地址进行了修改,在数据的后面存在一些残余的数据,
那些需要删除的数据。剩下的数据的位置可能不是原来的数据,但他们是不知道的。
调用erase()来删除那些残余的数据。
注意上面例子中通过erase()删除remove_if()的结果和vs.enc()范围的数据。


7. 综合例子:
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "Unit1.h"
//---------------------------------------------------------------------------

#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
#include <vector>
#include <assert.h>
using namespace std;

struct STResult
{
    double Time;
    double Xp;
    double Yp;
    int id;
};


//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
}


vector <STResult> ResultVector;


void __fastcall test()
{
    //test
    //vector <STResult> ResultVector;
    STResult stritem;
    stritem.Time = .1;
    stritem.Xp = .1;
    stritem.Yp = .1;
    stritem.id = 1;


    ResultVector.push_back( stritem );


}


//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
    test();
    assert(ResultVector[0].id == 1);
}
//---------------------------------------------------------------------------



C++ Vector用法深入剖析
C++编程语言中有一种叫做Vector的应用方法,它的作用在实际编程中是非常重要的。
在这里我们将会为大家详细介绍一下C++ Vector的相关应用技巧及基本内容,希望能给大家带来一些帮助。
(1)vector< 类型 > 标识符 ;
(2)vector< 类型 > 标识符(最大容量) ;
(3)vector< 类型 > 标识符(最大容量,初始所有值);
(4) int i[4] = {12,3,4,5};
    vector< 类型 > vi(i , i+2); //得到i索引值为3以后的值 ;  
(5)vector< vector<int> >   //vi 定义2维的容器;记得一定要有空格,不然会报错


  vector< int > line   
  // 在使用的时候一定要首先将vi个行进行初始化;   
  for(int i = 0 ; i < 10 ; i ++)  
  {  
    vector.push_back(line);  
  }  


  /// 个人认为使用vector定义二维数组很好,因为是长度可以不预先确定。很好。 


(6)C++ Vector排序
  vector< int > vi ;   
  vi.push_back(1);  
  vi.push_back(3);  
  vi.push_back(0);  


  sort(vi.begin() , vi.end()); /// /小到大  
  reverse(vi.begin(),vi.end()) /// 从大道小 


(7)顺序访问
  vector < int > vi ;   
  for( int i = 0 ; i < 10 ; i ++)  
  {  
    vector.push_back(i);  
  } 
  
  for(int i = 0 ; i < 10 ; i ++) /// 第一种调用方法  
  {  
    cout <<vector[i] <<" " ;   
  } 
 
  for(vector<int>::iterator it = vi.begin() ; 
  it !=vi.end() ; it++) ///第二种调用方法  
  {  
    cout << *it << " " ;  
  }
 
(8)寻找
vector < int > vi ;   
for( int i = 0 ; i < 10 ; i ++)  
{  
  vector.push_back(i);  

  
vector < int >::interator it = find(vi.begin() , vi.end,3) ;  
cout << *it << endl ; ///返回容器内找到值的位置。 


(9)使用数组对C++ Vector进行初始化
int i[10] ={1,2,3,4,5,6,7,78,8} ;  


///第一种   
vector<int> vi(i+1,i+3); ///从第2个元素到第三个元素  
for(vector <int>::interator it = vi.begin() ; it != vi.end() ; it++)  
{  
  cout << *it <<" " ;   



(10) 结构体类型
struct temp  
{  
public :  
  string str ;   
public :  
  int id ;  
}tmp
  
int main()  
{  
  vector <temp> t ;   
  temp w1 ;   
  w1.str = "Hellowor" ;  
  w1.id = 1 ;   
  t.push_back(t1);  
  cout << w1.str << "," <<w1.id <<endl ;   
  return 0 ;   



vector 容器

vectorC++标准模版库(STL,Standard Template Library)中的部分内容。之所以认为是一个容器,是因为它能够像容器一样存放各种类型的对象,简单的说:vector是一个能够存放任意类型的动态数组,能够增加和压缩数据。

使用vector容器之前必须加上<vector>头文件:#include<vector>;

vector属于std命名域的内容,因此需要通过命名限定:using std::vector;也可以直接使用全局的命名空间方式:using namespace std;

 

vector成员函数

c.push_back(elem)在尾部插入一个elem数据。

    vector<int> v;
    v.push_back(1);

c.pop_back()删除末尾的数据。

    vector<int> v;
    v.pop_back();

c.assign(beg,end)将[beg,end)一个左闭右开区间的数据赋值给c。

vector<int> v1,v2;
v1.push_back(10);
v1.push_back(20);
v2.push_back(30);
v2.assign(v1.begin(),v1.end());

c.assign (n,elem)将n个elem的拷贝赋值给c。

vector<int> v;

v.assign(5,10);//往v里放5个10

c.at(int index)传回索引为index的数据,如果index越界,抛出out_of_range异常。

vecto<int> v;
cout << v.at(2) << endl;//打印vector中下标是2的数据

c.begin()返回指向第一个数据的迭代器。

c.end()返回指向最后一个数据之后的迭代器。

复制代码
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
vector<int>::iterator it;
for(it = v.begin();it!=v.end();it++){
    cout << *it << "\t";
}
cout << endl;
复制代码

c.rbegin()返回逆向队列的第一个数据,即c容器的最后一个数据。

c.rend()返回逆向队列的最后一个数据的下一个位置,即c容器的第一个数据再往前的一个位置。

复制代码
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
vector<int>::reverse_iterator it;
for(it = v.rbegin();it!=v.rend();it++){
    cout << *it << "\t";
}
cout << endl;
复制代码

c.capacity()返回容器中数据个数,翻倍增长。

复制代码
vector<int> v;
v.push_back(1);
cout << v.capacity() << endl;  // 1
v.push_back(2);
cout << v.capacity() << endl;  // 2
v.push_back(3);
cout << v.capacity() << endl; // 4
复制代码

c.clear()移除容器中的所有数据。

复制代码
vector<int>::iterator it;
for(it = v.begin();it!=v.end();it++){
    cout << *it << "\t";
}
v.clear();
for(it = v.begin();it!=v.end();it++){
    cout << *it << "\t";
}
cout << endl;
复制代码

c.empty()判断容器是否为空。

复制代码
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
if(!v.empty()){
    cout << "v is not empty!" << endl;        
}
复制代码

c.erase(pos)删除pos位置的数据,传回下一个数据的位置。

vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.erase(v.begin());

c.erase(beg,end)删除[beg,end)区间的数据,传回下一个数据的位置。

vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.erase(v.begin(),v.end());

c.front()返回第一个数据。

c.back()传回最后一个数据,不检查这个数据是否存在。

复制代码
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
if(!vec.empty()){
    cout << “the first number is:” << v.front() << endl;
    cout << “the last number is:” << v.back() << endl;
}
复制代码

c.insert(pos,elem) 在pos位置插入一个elem的拷贝,返回插入的值的迭代器。

c.insert(pos,n,elem)在pos位置插入n个elem的数据,无返回值。

c.insert(pos,beg,end)在pos位置插入在[beg,end)区间的数据,无返回值。

vector<int> v;
v.insert(v.begin(),10);
v.insert(v.begin(),2,20);
v.insert(v.begin(),v1.begin(),v1.begin()+2);

c.size()返回容器中实际数据的个数。

c.resize(num)重新指定队列的长度。(往往用来增加vector的长度,小->大 ok 大->小 没用!)

c.reserve()保留适当的容量。

  针对resize()和reserver()做一点分析:

  reserve是容器预留空间,但并不真正创建元素对象,在创建对象之前,不能引用容器内的元素,因此当加入新的元素时,需要用push_back()/insert()函数。

  resize是改变容器的大小,并且创建对象,因此,调用这个函数之后,就可以引用容器内的对象了,因此当加入新的元素时,用operator[]操作符,或者用迭代器来引用元素对象。

  再者,两个函数的形式是有区别的,reserve函数之后一个参数,即需要预留的容器的空间;resize函数可以有两个参数,第一个参数是容器新的大小,第二个参数是要加入容器中的新元素,如果这个参数被省略,那么就调用元素对象的默认构造函数。

   reserve只是保证vector的空间大小(capacity)最少达到它的参数所指定的大小n。在区间[0, n)范围内,如果下标是index,vector[index]这种访问有可能是合法的,也有可能是非法的,视具体情况而定。
     resize和reserve接口的共同点是它们都保证了vector的空间大小(capacity)最少达到它的参数所指定的大小。

c.max_size()返回容器能容量的最大数量。

c1.swap(c2)将c1和c2交换。

swap(c1,c2)同上。

vector<int> v1,v2,v3;
v1.push_back(10);
v2.swap(v1);
swap(v3,v1);

vector<type>c;创建一个空的vector容器。

vector<type> c1(c2);复制一个vector。

vector<type> c(n);创建一个vector,含有n个数据,数据均以缺省构造产生,即全0;

vector<type> c(n,elem)创建一个vector,含有n个elem的拷贝数据。

vector<type> c(beg,end)创建一个以[beg,end)区间的vector。

~vector<type>()   销毁所有数据,施放内存。

 

压缩一个臃肿的vector

很多时候大量的删除数据,或者通过使用reserver(),结果vector的空间远远大于实际的需要。所以需要压缩vector到它的实际大小。resize()能增加vector的大小。clear()仅仅移除容器内的数据,不能改变capacity()的大小,所以对vector进行压缩非常重要。

测试一下clear()函数:

复制代码
 1 //
 2 //  vector.cpp
 3 //  vector
 4 //
 5 //  Created by scandy_yuan on 13-1-7.
 6 //  Copyright (c) 2013年 Sam. All rights reserved.
 7 //
 8 
 9 #include <iostream>
10 #include <vector>
11 using namespace std;
12 int main(int argc, const char * argv[])
13 {
14 
15     // insert code here...
16     vector<int> v;
17     v.push_back(1);
18     v.push_back(2);
19     v.push_back(3);
20     vector<int>::iterator it;
21     cout << "clear before:" << " ";
22     for(it=v.begin();it!=v.end();it++){
23         cout << *it << "\t";
24     }
25     cout << endl;
26     cout << "clear before capacity:" << v.capacity() << endl;
27     v.clear();
28     cout << "after clear:" << " ";
29     for(it=v.begin();it!=v.end();it++){
30         cout << *it << "\t";
31     }
32     cout << endl;
33     cout << "after clear capacity:" << v.capacity() << endl;
34     return 0;
35 }
复制代码

结果:

clear before: 1    2    3    
clear before capacity:4
after clear: 
after clear capacity:4

为什么这里打印的capacity()的结果是4不做详细解释,请参考上面关于capacity的介绍。 通过结果,我们可以看到clear()之后数据全部清除了,但是capacity()依旧是4。

假设:我们通过原本的vector来创建一个新的vector,让我们看看将会发生什么?

复制代码
 1 //
 2 //  vector.cpp
 3 //  vector
 4 //
 5 //  Created by scandy_yuan on 13-1-7.
 6 //  Copyright (c) 2013年 Sam. All rights reserved.
 7 //
 8 
 9 #include <iostream>
10 #include <vector>
11 using namespace std;
12 int main(int argc, const char * argv[])
13 {
14 
15     // insert code here...
16     vector<int> v;
17     v.push_back(1);
18     v.push_back(2);
19     v.push_back(3);
20     cout << "v.capacity()" << v.capacity() << endl;
21     
22     vector<int> v1(v);
23     cout << "v1.capacity()" << v1.capacity() << endl;
24     return 0;
25 }
复制代码

结果:

v.capacity()4
v1.capacity()3

可以看出,v1的capacity()是v的实际大小,因此可以达到压缩vector的目的。但是我们不想新建一个,我们想在原本的vector(即v)上进行压缩,那么借鉴上面的方式思考另一种方式。

假设:我们通过swap函数把v1交换回v,看看会发生什么?

复制代码
 1 //
 2 //  vector.cpp
 3 //  vector
 4 //
 5 //  Created by scandy_yuan on 13-1-7.
 6 //  Copyright (c) 2013年 Sam. All rights reserved.
 7 //
 8 
 9 #include <iostream>
10 #include <vector>
11 using namespace std;
12 int main(int argc, const char * argv[])
13 {
14 
15     // insert code here...
16     vector<int> v;
17     v.push_back(1);
18     v.push_back(2);
19     v.push_back(3);
20     cout << "v.capacity()" << v.capacity() << endl;
21     
22     vector<int> v1(v);
23     cout << "v1.capacity()" << v1.capacity() << endl;
24     
25     v.swap(v1);
26     cout << "v.swap(v1).capacity()" << v.capacity() << endl;
27     return 0;
28 }
复制代码

结果:

v.capacity()4
v1.capacity()3
v.swap(v1).capacity()3

可以看出,v.capacity()变成了3,目的达到。但是代码给人感觉繁琐臃肿,我们从新考虑一种新的写法,采用匿名对象来代替v1这个中间对象:vector<int> (v).swap(v);

测试:

复制代码
 1 //
 2 //  vector.cpp
 3 //  vector
 4 //
 5 //  Created by scandy_yuan on 13-1-7.
 6 //  Copyright (c) 2013年 Sam. All rights reserved.
 7 //
 8 
 9 #include <iostream>
10 #include <vector>
11 using namespace std;
12 int main(int argc, const char * argv[])
13 {
14 
15     // insert code here...
16     vector<int> v;
17     v.push_back(1);
18     v.push_back(2);
19     v.push_back(3);
20     cout << "v.capacity()" << v.capacity() << endl;
21     
22     vector<int> (v).swap(v);
23     cout << "v.capacity()" << v.capacity() << endl;
24     return 0;
25 }
复制代码

结果:

v.capacity()4
v.capacity()3

可以看到 v.capacity()由4编程了3,目的达到。


之前没有关注C++11,感谢@egmkang,确实在C++11中已经提供了shrink_to_fit()函数实现vector的压缩。

如下:

复制代码
 1 #include <iostream>
 2 #include <vector>
 3 int main()
 4 {
 5     std::vector<int> v;
 6     std::cout << "Default-constructed capacity is " << v.capacity() << '\n';
 7     v.resize(100);
 8     std::cout << "Capacity of a 100-element vector is " << v.capacity() << '\n';
 9     v.clear();
10     std::cout << "Capacity after clear() is " << v.capacity() << '\n';
11     v.shrink_to_fit();
12     std::cout << "Capacity after shrink_to_fit() is " << v.capacity() << '\n';
13 }
复制代码

结果:

Default-constructed capacity is 0
Capacity of a 100-element vector is 100
Capacity after clear() is 100
Capacity after shrink_to_fit() is 0

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值