【C++】STL:vector

目录

vector的基本功能

emplace_back() 和 push_back() 的区别

添加与修改

迭代器

insert和erase


vector的基本功能

下面所用到的名词“元素”和“对象”是对等的。

函数名称功能
push_back在尾部添加一个元素
emplace_back在尾部添加一个元素
pop_back在尾部删除一个元素
clear清空所有元素
at按索引访问某个位置的元素
front返回头元素
back返回尾元素
size返回元素的个数
capacity返回当前容量
resize改变容量大小
insert在中间插入元素
erase删除中间的元素

vector工作流程:

首先vector会申请一个buffer缓冲区,capacity就表示该缓冲区的大小(是实际分配内存的),size就表示缓冲区已经被使用了多少(返回的是对象的数量,记住只和对象有关),reserve修改capacity的大小,不修改size的大小,也就是不会分配具体的对象,resize修改缓冲区大小,修改了size和capacity的大小,也就是给缓冲区分配对象。

emplace_back() 和 push_back() 的区别

区别在于底层实现的机制不同。

  • push_back() 向容器尾部添加元素时,首先会创建这个元素,然后再将这个元素拷贝(调用拷贝构造函数)或者移动(调用移动构造函数)到容器中(如果是拷贝的话,事后会自行销毁先前创建的这个元素)。
  • 而 emplace_back() 在实现时,则是直接在容器尾部创建这个元素,省去了拷贝或移动元素的过程。

push_back()

可以通过使用容器对象的 push_back() 函数,在序列的末尾添加一个元素。例如:

std::vector<double> values;
values.push_back(3.1415926);

在这个示例中,push_back() 函数以传入的参数 -3.1415926 作为新元素的值,然后把它添加到现有元素的后面。因为这里并没有现有的元素,所以这个元素就是第一个元素。如果没有调用 reserve(),容器就会为这个新元素分配内存。这里,第二个版本的 push_back() 使用了右值引用参数,这样就可以通过移动运算来添加元素。例如:

std::vector<std::string> words;
words.push_back(string("adiabatic"));
// Move string("adiabatic") into the vector

这里 push_back() 的参数是一个临时对象,因此这会调用右值引用版的函数。当然,也可以这样写:

words.push_back ("adiabaticft"); // Move string("adiabatic") into the vector

编译器会生成一个以"adiabatic”为初值的 string 对象,然后这个对象会像前面那样移动到 vector 中。 

emplace_back()

还有一个更好的方法来添加元素。emplace back() 比 push_back() 更有效率。下面这个代码片段说明了为什么:

std::vector<std::string> words;
words.push_back (std:: string ("facetious") ) ; // Calls string constructor & moves the string object 
words•emplace_back("abstemious");// Calls string constructor to create element in place

emplace_back() 的参数正是添加到容器中的对象的构造函数所需要的参数。emplace_back() 用它的参数作为构造函数的参数,在容器中生成对象。如果不想使用移动运算,这个示例中就要使用 push_back()。可以在 emplace_back() 函数中使用尽可能多的参数,只要它们满足对象构造函数的要求。这里有一个使用多参数的 emplace_back() 的示例:

std::string str {"alleged"};
words.emplace_back(str, 2, 3);
// Create string object corresponding to "leg" in place

emplace_back() 函数会调用接收三个参数的 string 构造函数,生成 string 对象,然后把它添加到 words 序列中。构造函数会生成一个从索引 2 幵始、包含 str 中三个字符的子串。

添加与修改

#include "stdio.h"
#include "string.h"
#include "vector"
#include "iostream"
#include "sstream"
#include "string"
using namespace std;
string itos(int i)
{
    stringstream s;
    s << i;
    return s.str();
}

int main()
{
    vector<int> arr(128);
    int capacity = arr.capacity();
    int size = arr.size();

    string capacity_s = itos(capacity);
    string size_s = itos(size);
    const char* capacity1 = capacity_s.c_str();
    const char* size1 = size_s.c_str();
    cout << "capacity:" << capacity1 << endl; //结果为128
    cout << "size:" << size1 << endl; //结果也为128,因为还没有对这个vector进行操作,vector自己初始化了,内部是128个0

    arr[0] = 1;
    arr[1] = 2;
    arr.at(2) = 222;
    printf("%d", arr.size());
    const char* capacity2 = itos(arr.capacity()).c_str();
    const char* size2 = itos(arr.size()).c_str();
    cout << "capacity:" << capacity2 << endl; //结果为128
    cout << "size:" << size2 << endl; //size也是128,因为我们初始化了,里面已经有对象了,是128个0,现在仅仅是被我们修改了其中的几个数值而已,所以size还是128

    arr.push_back(123);
    const char* capacity3 = itos(arr.capacity()).c_str();
    const char* size3 = itos(arr.size()).c_str();
    cout << "capacity:" << capacity3 << endl; //结果为256
    cout << "size:" << size3 << endl; //size也是129


    cout << "end" << endl;
    return 0;
}

结果为:

 

从面结果可以看出,当初始化为128后,其capacity和size的大小都是128,这是用[]是可以修改其中的值的,但是如果这时使用push_back,又因为size==capacity,已经没有空间添加新的元素,这是vector会自动更改capacity的大小(具体更改方式根据编译器和平台有关系,我这台电脑是直接变成128的2倍,也就是256),由于添加了一个对象,这时size的大小变为129。

从这个结果我们分析得出,如果你不使用vector的初始化,此时capacity和size的大小都为0,这时使用push_back就会不停的申请内存空间,严重影响效率。所以在使用vector时,最好进行初始化,预先申请一定的空间。

迭代器

#include "stdio.h"
#include "string.h"
#include "vector"
#include "iostream"
#include "sstream"
#include "string"
using namespace std;
string itos(int i)
{
    stringstream s;
    s << i;
    return s.str();
}

int main()
{
    vector<int> arr(128);
    int capacity = arr.capacity();
    int size = arr.size();

    string capacity_s = itos(capacity);
    string size_s = itos(size);
    const char* capacity1 = capacity_s.c_str();
    const char* size1 = size_s.c_str();
    cout << "capacity:" << capacity1 << endl; //结果为128
    cout << "size:" << size1 << endl; //结果也为128,因为还没有对这个vector进行操作,vector自己初始化了,内部是128个0

    arr[0] = 1;
    arr[1] = 2;
    arr.at(2) = 222;
    printf("%d", arr.size());
    const char* capacity2 = itos(arr.capacity()).c_str();
    const char* size2 = itos(arr.size()).c_str();
    cout << "capacity:" << capacity2 << endl; //结果为128
    cout << "size:" << size2 << endl; //size也是128

    arr.push_back(123);
    const char* capacity3 = itos(arr.capacity()).c_str();
    const char* size3 = itos(arr.size()).c_str();
    cout << "capacity:" << capacity3 << endl; //结果为128
    cout << "size:" << size3 << endl; //size也是128

    //使用就是这么使用,具体为啥会这样还得继续学习
    vector<int>::iterator iter;
    for(iter = arr.begin(); iter != arr.end(); iter++)
    {
        int& value = *iter;
        printf("%d", value);
    }


    cout << "end" << endl;
    return 0;
}

结果为:

insert和erase 

一般情况下不用insert和erase,因为这是非常低效的。比如删除第一个对象,那么就要将后面所有的对象都向前移动,这是非常消耗cpu的,插入也是。所以这里就不介绍insert和erase了。

所以一般情况下,插入删除的操作都会使用链表。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值