vector 详细用法 C++

本文详细介绍了C++ STL中的vector容器的使用方法,包括常用成员函数的实现细节和内部工作原理,并通过示例代码验证了这些函数的功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

       使用STL的三个境界:能用,明理,能扩展。本文属于第一个境界,如果结合了《STL源码解析》,则达到了第二个境界,如果项目中有需要,对STL进行了扩展则就达到了第三个境界!如果希望深刻理解vector的这些个成员函数,最好的办法是详细了解其内部实现,《STL源码解析》是个好途径!当然,也可以直接看编译器自带的<vector>的源码。

       vector是C++标准模板库中的部分内容,vector之所以被认为是一个容器,是因为它能够像容器一样存放各种类型的对象,简单地说,vector是一个能够存放任意类型的动态数组。
       为了使用vector,必须包含头文件<vector>。另,vector属于std命名空间,因此需要通过命名限定,可以有如下三种方式,后两种方式更好,因为未引入的无关的内容。(依稀记的《Effective C++》的某个条款这个提过!)
using namespace std;
using namespace std::vector;
std::vector<int> vec;


现在以 std::vector<int> vec为例,描述相关函数的功能!

第一部分:

vec.begin()//指向迭代器中第一个元素。 
vec.end()//指向迭代器中末端元素的下一个,指向一个不存在元素。		
vec.push_back(elem)		//在尾部加入一个数据。
vec.pop_back()			//删除最后一个数据。
vec.capacity()	//vector可用空间的大小。
vec.size()//返回容器中数据个数。
vec.empty()	//判断容器是否为空。
vec.front()		//传回第一个数据。
vec.back()	//传回最后一个数据,不检查这个数据是否存在。
vec.at(index)	//传回索引idx所指的数据,如果idx越界,抛出out_of_range。
vec.clear()	//移除容器中所有数据。
vec.erase(iterator)	//删除pos位置的数据,传回下一个数据的位置。
vec.erase(begin,end)	//删除[beg,end)区间的数据,传回下一个数据的位置。注意:begin和end为iterator
vec.insert(position,elem)	//在pos位置插入一个elem拷贝,传回新数据位置。
vec.insert(position,n,elem)	//在pos位置插入n个elem数据,无返回值。
vec.insert(position,begin,end)	//在pos位置插入在[beg,end)区间的数据,无返回值。

以下代码验证上述这些常用函数的功能:

#include<vector>
#include<iostream>

using namespace std;


int main()
{
    vector<int> vec(3,0);
    vector<int>::iterator iter;
    vector<int>::iterator begin=vec.begin();
    vector<int>::iterator end=vec.end();
    cout<<"vec:";
    for(iter=begin; iter!=end; iter++)
    {
        static std::size_t i=0;
        cout<<*iter<<",";
        i++;
    }
    cout<<endl;
    cout<<"size:"<<vec.size()<<endl;
    cout<<"capacity:"<<vec.capacity()<<endl;
//////////////////////////////////////////////////
    cout<<endl;
    vec.push_back(1);
    vec.push_back(2);

    begin=vec.begin();
    end=vec.end();
    cout<<"push back 1 and 2 based on above;vec:";
    for(iter=begin; iter!=end; iter++)
    {
        static std::size_t j=0;
        cout<<*iter<<",";
        j++;
    }
    cout<<endl;
    cout<<"size:"<<vec.size()<<endl;
    cout<<"capacity:"<<vec.capacity()<<endl;
//////////////////////////////////////////////////
    cout<<endl;
    vec.pop_back();

    begin=vec.begin();
    end=vec.end();
    cout<<"pop one element based on above;vec:";
    for(iter=begin; iter!=end; iter++)
    {
        static std::size_t k=0;
        cout<<*iter<<",";
        k++;
    }
    cout<<endl;
    cout<<"size:"<<vec.size()<<endl;
    cout<<"capacity:"<<vec.capacity()<<endl;
/////////////////////////////////////////////////
    begin=vec.begin();
    end=vec.end();
    cout<<endl;
    if(vec.empty())
    {
        cout<<"vec is empty"<<endl;
    }
    else
    {
        cout<<"vec is not empty"<<endl;
    }
/////////////////////////////////////////////////  
    cout<<endl;
    cout<<"based on the above:"<<endl;
    cout<<"     vec.front():"<<vec.front()<<endl;
    cout<<"     vec.back():"<<vec.back()<<endl;
    begin=vec.begin();
    end=vec.end();
    cout<<"     size:"<<vec.size()<<endl;
    cout<<"     capacity:"<<vec.capacity()<<endl;
    cout<<"vec:";
    for(iter=begin; iter!=end; iter++)
    {
        static std::size_t l=0;
        cout<<*iter<<",";
        l++;
    }
    cout<<endl;
////////////////////////////////////////////////////
    cout<<endl;
    cout<<"call at(),based on the above:"<<endl;
    cout<<"     vec.at():"<<vec.at(3)<<endl;
    begin=vec.begin();
    end=vec.end();
    cout<<"     size:"<<vec.size()<<endl;
    cout<<"     capacity:"<<vec.capacity()<<endl;
    cout<<"vec:";
    for(iter=begin; iter!=end; iter++)
    {
        static std::size_t m=0;
        cout<<*iter<<",";
        m++;
    }
    cout<<endl;
//////////////////////////////////////////////////
    cout<<endl;
    cout<<"call clear(),based on the above:"<<endl;
    vec.clear();
    begin=vec.begin();
    end=vec.end();
    cout<<"     size:"<<vec.size()<<endl;
    cout<<"     capacity:"<<vec.capacity()<<endl;
    cout<<"vec:";
    for(iter=begin; iter!=end; iter++)
    {
        static std::size_t m=0;
        cout<<*iter<<",";
        m++;
    }
    cout<<endl;
//////////////////////////////////////////////////
    cout<<endl;
    for(int i=1;i<8;i++)
    {
        vec.push_back(i);
    }
    cout<<"push_back 1,2,3,4,5,6,7 based on above;vec:";
    begin=vec.begin();
    end=vec.end();
    for(iter=begin; iter!=end; iter++)
    {
        static std::size_t m=0;
        cout<<*iter<<",";
        m++;
    }
////////////////////////////
    cout<<endl;
    vec.erase(vec.begin()+2);
    cout<<"call vec.erase(3),vec:";
    begin=vec.begin();
    end=vec.end();
    for(iter=begin; iter!=end; iter++)
    {
        static std::size_t m=0;
        cout<<*iter<<",";
        m++;
    }
    cout<<endl;
    cout<<"     size:"<<vec.size()<<endl;
    cout<<"     capacity:"<<vec.capacity()<<endl;
//////////////////////////
    cout<<endl;
    vec.erase(vec.begin()+1,vec.begin()+3);
    cout<<"call vec.erase(1,3),vec:";
    begin=vec.begin();
    end=vec.end();
    for(iter=begin; iter!=end; iter++)
    {
        static std::size_t m=0;
        cout<<*iter<<",";
        m++;
    }
    cout<<endl;
    cout<<"     size:"<<vec.size()<<endl;
    cout<<"     capacity:"<<vec.capacity()<<endl;
    return 1;<span style="font-family: Arial, Helvetica, sans-serif;">}</span>

输出结果如下:


vector中v[i]与v.at(i)的区别:参见:http://www.cnblogs.com/zhuyf87/archive/2012/12/06/2805579.html

void f(vector<int> &v)
{
  v[0];    // A
  v.at[0];  // B
}

      如果v非空,A行和B行没有任何区别。如果v为空,B行会抛出std::out_of_range异常,A行的行为未定义。
      c++标准不要求vector<T>::operator[]进行下标越界检查,原因是为了效率,总是强制下标越界检查会增加程序的性能开销。设计vector是用来代替内置数组的,所以效率问题也应该考虑。不过使用operator[]就要自己承担越界风险了。如果需要下标越界检查,请使用at。

第二部分:

assign函数原型及功能:
void assign(const_iterator first,const_iterator last); //功能:将区间[first,last)的元素赋值到当前的vector中,当前vector会清除掉容器中之前的内容。
void assign(size_type n,const T& x = T()); //功能:赋n个值为x的元素到当前vector中,当前vector会清除掉容器中之前的内容。

以下函数验证assign函数的功能:

#include <vector>
#include <iostream>
using namespace std;
int main( )
{
    vector<int> v1, v2, v3;
    vector<int>::iterator iter;
    for(int i=10; i<60; i+=10)
    {
        v1.push_back(i);
    }
    v2.push_back(1);
    v2.push_back(2);

    cout << "v1 = " ;
    for (iter = v1.begin(); iter != v1.end(); iter++)
    {
        cout << *iter << " ";
    }
    cout << endl;

    cout << "v2 = ";
    for (iter = v2.begin(); iter != v2.end(); iter++)
        cout << *iter << " ";
    cout << endl;


    v1.assign(v2.begin(), v2.end());
    cout << "v2 = ";
    for (iter = v2.begin(); iter != v2.end(); iter++)
        cout << *iter << " ";
    cout << endl;
    v3=v1;
    v3.assign(4,3) ;
    cout << "v3 = ";
    for (iter = v3.begin(); iter != v3.end(); iter++)
        cout << *iter << " ";
    cout << endl;
    return 0;
}
运行结果如下:

第三部分:

vec.rbegin()//传回一个vector的最后一个数据的指针。
vec.rend()// 传回一个vector的第一个数据前一个位置的指针。?
验证代码如下:
#include <vector>
#include <iostream>
using namespace std;
int main( )
{
    vector<int> v1, v2, v3;
    vector<int>::iterator iter;
    for(int i=10; i<60; i+=10)
    {
        v1.push_back(i);
    }
    v2.push_back(1);
    v2.push_back(2);

    cout << "v1 = " ;
    for (iter = v1.begin(); iter != v1.end(); iter++)
    {
        cout << *iter << " ";
    }
    cout << endl;

    cout << "v2 = ";
    for (iter = v2.begin(); iter != v2.end(); iter++)
        cout << *iter << " ";
    cout << endl;
    vector<int>::reverse_iterator r_iter;
    cout << "v1 in reverse ";
    for (r_iter = v1.rbegin(); r_iter != v1.rend(); r_iter++)
        cout << *r_iter << " ";
    cout << endl;
    cout<<"v1.rbegin():"<<*v1.rbegin()<<endl;
    cout<<"v1.rbegin():"<<(*(v1.rbegin()--))<<endl;
    cout<<"v1.rend()--:"<<*(v1.rend()--)<<endl;

    cout<<"v1.rend()++:"<<*(v1.rend()++)<<endl;

    return 0;
}
输出结果为:



        此处有个疑问:对(*(v1.rbegin()++))、(*(v1.begin()++))、(*(v1.rbegin()--))、(*(v1.begin()--))均没达到预期,需要看下其内部究竟是怎么实现的!

        另外,注意:企图直接打印迭代器,编译是通不过的!eg:cout<< v1.begin();

第四部分:

vec.resize(num)//重新指定vector的长度。
vec.resize(num,value)//重新指定vector的长度。并设定新增的元素的值
当需要以vec[size+1]=vec[j];的方式对超过vector的size赋值时,都需要先调用下resize()函数,如果直接对超出vector.size()的位置赋值,编译不能通过!
如上所示,一种是仅仅设定size,另一种即设定size也设定value;其实resize函数就是重新设定finish指针。如果在调用resize函数时,发现vector没有剩余的空间了,则会以当前的size为基础,申请开辟2倍的空间。(开辟空间,拷贝,释放原有空间的过程)

第五部分:

vec.swap(vec1)//
swap(vec,vec1)//

#include<vector>
#include<iostream>

using namespace std;

int main()
{
    vector<int> vec(3,0);
    vector<int>::iterator iter;
    vector<int>::iterator begin=vec.begin();
    vector<int>::iterator end=vec.end();
    cout<<"vec:";
    for(iter=begin; iter!=end; iter++)
    {
        static std::size_t i=0;
        cout<<*iter<<",";
        i++;
    }
    cout<<endl;
    vec.push_back(7);
    cout<<"size:"<<vec.size()<<endl;
    cout<<"capacity:"<<vec.capacity()<<endl;
    vector<int>(vec).swap(vec);
    cout<<"vector<int>(vec)-swap-capacity:"<<vec.capacity()<<endl;
    cout<<"vector<int>(vec)-swap-size:"<<vec.size()<<endl;


    {
        vector<int> temp(vec);
        temp.swap(vec);
        cout<<"temp-swap-capacity:"<<vec.capacity()<<endl;
        cout<<"temp-swap-size:"<<vec.size()<<endl;
    }


    vector<int>().swap(vec);
    cout<<"vector<int>()-swap-capacity:"<<vec.capacity()<<endl;
    cout<<"vector<int>()-swap-size:"<<vec.size()<<endl;
     return 1;
}
输出结果为:


#include<vector>
#include<iostream>
#include<algorithm>
using namespace std;


int main()
{
    vector<int> vec(3,0);
    vector<int>::iterator iter;
    vector<int>::iterator begin=vec.begin();
    vector<int>::iterator end=vec.end();
    cout<<"vec:";
    for(iter=begin; iter!=end; iter++)
    {
        static std::size_t i=0;
        cout<<*iter<<",";
        i++;
    }
    cout<<endl;
    vec.push_back(7);
    cout<<"vec size:"<<vec.size()<<endl;
    cout<<"vec capacity:"<<vec.capacity()<<endl;

    vector<int> vec1(3,1);
    vec1.push_back(6);
    cout<<"vec1 size:"<<vec1.size()<<endl;
    cout<<"vec1 capacity:"<<vec1.capacity()<<endl;

    swap(vec,vec1);
    begin=vec.begin();
    end=vec.end();
    cout<<"after swap vec:";
    for(iter=begin; iter!=end; iter++)
    {
        cout<<*iter<<",";
    }
    cout<<"vec size after swap():"<<vec.size()<<endl;
    cout<<"vec capacity after swap():"<<vec.capacity()<<endl;

    begin=vec1.begin();
    end=vec1.end();
    cout<<"after swap vec1:";
    for(iter=begin; iter!=end; iter++)
    {
        cout<<*iter<<",";
    }
    cout<<"vec1 size after swap():"<<vec1.size()<<endl;
    cout<<"vec1 capacity after swap():"<<vec1.capacity()<<endl;
    return 0;
}
输出结果为:

该结果表明<algorithm>中的函数swap(),只是交换两个vector中的内容,其原本的size和capacity均不做改变!

vec.reserve()//设定capacity的值,如果小于原本的capacity的值则保持为原本的capacity的值。

以下为显而易见的操作:
operator[]://此函数返回的是容器中指定位置的一个引用。
operattor*://指针的取址操作

若干种创建方式(vector的构造函数)
vector<type> vec
vector<type> vec(vec1)
vector<type> vec=vec1
vector<type> vec(n)
vector<type> vec(n,elem)
vector<type> vec(begin,end)
vector<type> vec{a,b,c,……}
vector<type> vec={a,b,c,……}

<think>好的,用户想要详细讲解C++vector用法。首先,我需要确定用户的知识水平,可能已经了解基础C++,但对STL容器还不熟悉。接下来,得覆盖vector的基本概念、常用操作和一些高级用法。 首先,我应该从vector是什么开始,它是动态数组,可以自动管理内存,这样用户能明白和普通数组的区别。然后,初始化部分,不同的构造方法,比如默认构造、指定大小、初始值、拷贝构造等。这里需要举例子,比如vector<int> v1; 或者vector<int> v2(5, 10); 这样用户更清楚。 接下来是元素访问,常用的方法如[]运算符、at()、front()、back(),还有data()。要提醒用户注意越界问题,at()会检查而[]不会,这点很重要。可能需要举例说明它们的区别。 然后是容量操作,比如size()、capacity()、empty()、reserve()、shrink_to_fit()。这里需要解释size和capacity的区别,以及reserve如何预先分配内存避免多次重新分配,提升效率。可能用代码示例说明reserve的作用。 元素操作部分,添加元素用push_back()、emplace_back(),插入insert(),删除pop_back()、erase()、clear()。要强调emplace_back()和push_back()的区别,前者更高效,避免不必要的拷贝。插入和删除时迭代器失效的问题可能需要提到,但用户可能还没学到迭代器,所以简单带过还是详细说明呢?如果用户是初学者,可能暂时不需要深入,但作为详细讲解,还是应该提一下注意事项。 迭代器部分,begin()、end()等,以及如何使用范围for循环。这部分可能需要示例代码,比如遍历vector并输出元素。 最后,性能注意事项,比如在尾部添加元素高效,中间或头部插入删除低效,以及预分配内存的好处。同时,可以对比vector和其他容器如list、deque的适用场景。 用户可能的问题:如何高效使用vector?什么时候用reserve?emplace_back和push_back的区别?迭代器失效的情况?需要确保这些点在讲解中都有覆盖。 另外,用户可能需要实际代码示例来理解每个方法的用法,所以每个部分都应该有对应的代码片段。比如插入元素的例子,删除元素的例子,reserve的例子等。 还要注意结构清晰,分点讲解,每个部分用标题分开,方便用户逐步理解。可能分为概述、初始化、元素访问、容量操作、元素操作、迭代器、性能注意事项等部分。 需要检查是否有遗漏的重要知识点,比如C++11后的新特性,emplace_back、shrink_to_fit(),移动语义对vector的影响,但可能用户暂时不需要太深入,但作为详细讲解应该提到。 最后,确保所有代码示例正确,语法正确,比如使用正确的迭代器循环,范围for循环的写法,避免常见错误,比如在循环中插入元素导致迭代器失效的情况,虽然可能不在此次讲解范围内,但可以提醒用户注意。 总结:结构需要清晰,分步骤讲解,每个功能点配示例代码,强调重要注意事项,帮助用户正确高效地使用vector。</think>以下是对C++中`vector`用法的分步详解,涵盖初始化、操作和性能优化: --- ### 一、vector概述 `vector`是C++标准模板库(STL)中的**动态数组**,特点: - 自动管理内存,动态扩展/收缩 - 支持随机访问(时间复杂度$O(1)$) - 尾部操作高效,中间/头部操作低效 - 需包含头文件:`#include <vector>` --- ### 二、初始化方法 ```cpp // 默认构造(空vectorvector<int> v1; // 指定初始大小和值(5个100) vector<int> v2(5, 100); // 列表初始化(C++11) vector<int> v3 = {1, 2, 3, 4}; // 拷贝构造 vector<int> v4(v3); // 通过数组初始化 int arr[] = {10, 20, 30}; vector<int> v5(arr, arr + 3); ``` --- ### 三、元素访问 | 方法 | 说明 | 示例 | |-----------------|------------------------------|-----------------------| | `[]`运算符 | 无越界检查 | `v[0] = 5;` | | `at()` | 有越界检查(抛出异常) | `v.at(2) = 10;` | | `front()` | 访问首元素 | `int first = v.front()`| | `back()` | 访问末元素 | `int last = v.back()` | | `data()` | 获取底层数组指针(C++11) | `int* p = v.data();` | --- ### 四、容量操作 ```cpp vector<int> v = {1, 2, 3}; cout << v.size(); // 元素数量 → 3 cout << v.capacity(); // 实际分配的内存大小(≥size) cout << v.empty(); // 判空 → 0(false) v.reserve(100); // 预分配100个元素的内存 v.shrink_to_fit(); // 释放多余内存(capacity→size) ``` --- ### 五、元素操作 #### 1. 添加元素 ```cpp v.push_back(10); // 尾部插入(拷贝构造) v.emplace_back(20); // 更高效的尾部插入(直接构造) v.insert(v.begin() + 1, 99); // 在第二个位置插入99 ``` #### 2. 删除元素 ```cpp v.pop_back(); // 删除尾部元素 v.erase(v.begin()); // 删除首元素 v.erase(v.begin(), v.begin()+2); // 删除前两个元素 v.clear(); // 清空所有元素 ``` --- ### 六、迭代器使用 ```cpp vector<int> v = {10, 20, 30}; // 正向迭代器 for (auto it = v.begin(); it != v.end(); ++it) { cout << *it << " "; } // 反向迭代器 for (auto rit = v.rbegin(); rit != v.rend(); ++rit) { cout << *rit << " "; } // 范围for循环(C++11) for (int num : v) { cout << num << " "; } ``` --- ### 七、性能注意事项 1. **尾部操作**:`push_back`/`pop_back`时间复杂度为$O(1)$ 2. **中间操作**:插入/删除平均时间复杂度为$O(n)$ 3. **内存预分配**:使用`reserve()`减少扩容次数 4. **元素类型**:存储对象时优先用`emplace_back`代替`push_back` --- ### 八、综合示例 ```cpp #include <iostream> #include <vector> using namespace std; int main() { vector<int> nums; nums.reserve(5); // 预分配5个元素空间 // 添加元素 for (int i = 1; i <= 5; ++i) { nums.emplace_back(i * 10); } // 修改第二个元素 nums[1] = 999; // 删除最后一个元素 nums.pop_back(); // 遍历输出 for (auto num : nums) { cout << num << " "; // 输出:10 999 30 40 } return 0; } ``` --- ### 九、进阶技巧 1. **移动语义**:C++11后可用`vector<T>&&`实现高效转移 2. **自定义分配器**:控制内存分配策略 3. **vector<bool>**:特殊实现(使用位存储),需注意行为差异 如需更深入探讨特定用法,可进一步说明具体需求!
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值