目录
emplace_back() 和 push_back() 的区别
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了。
所以一般情况下,插入删除的操作都会使用链表。