做毕设,里面需要实现一个有关动态规划的算法,用到vector,map,set 这些容器(container) 。
vector 挺简单的,写这篇关于vector 的博客,有两个目的:
- 了解C++11中的几个新特性。(C++17都出来了,C++特性一点都不新呀...,姑且称为C++11新特性)
- 简单的知识更要熟练掌握啊,骚年。
我们平时写程序,都直接用C++11,没有什么问题!
可是我的毕设项目,不能用C++11,一用就出错,貌似是与项目中用到的 boost/shared_ptr 冲突了。
以下背景为粉红的都是C++11中才有的。
1. 示例程序1
下面介绍下vector 初始化,看程序1:
//程序1 test.cpp
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int main(){
//默认初始化
vector<string> vs1;
vs1.push_back("set");
vs1.push_back("deadlines");
vs1.push_back("for");
vs1.push_back("everything");
for(int i=0;i<vs1.size();++i){
cout<<vs1[i]<<' ';
}
cout<<endl;
//拷贝初始化vs2,把vs1里的元素全部赋给vs2
vector<string> vs2(vs1); //等同于,vector<string> vs2=vs1;
for(int i=0;i<vs2.size();++i){
cout<<vs2[i]<<' ';
}
cout<<endl;
vector<string> vs3;
//把vs1里的元素全部赋给vs3
vs3=vs1;
for(string i:vs3){
cout<<i<<' ';
}
cout<<endl;
return 0;
}
上面的程序,体现了两种初始化vector 的方式。
- 默认初始化,vector不含任何元素
- 拷贝初始化,很多类都有拷贝构造函数,用于拷贝初始化
此外,还有两种初始化方式:
- vector<string> svec(10, "hello") // sevc对象中有10个string类型元素---"hello"
- vector<string> svec={"are", "you", "OK"} // 列表初始化,C++11新特性
注:vector对象能高效增长,建议用默认初始化 [ 1 ] ,然后动态push_back添加元素。
事实上,定义vector对象时设定其元素,可能性能更差!
C++11新特性:范围for (range for)
程序1这样编译:
g++ -o test test.cpp
不会报错,会报一个警告。可是运行时会出错,原因在于,range for是C++11特性,必须这样编译:
g++ -std=C++11 -o test test.cpp
既然都用
范围for了,那么可以更方便一点,使用
auto类型说明符。
关于auto:
- 能自动推导出表达式类型
- auto一般会忽略顶层const,保留底层const,和decltype不同
- auto最常用的就是 推导类型auto i ; 和 推导引用类型auto &i ; 也常用与推导迭代器类型
2. vector 部分操作[1]
- v.empty() 如果v 不含任何元素,返回true ,否则false
- v.size() 返回v 中元素的个数
- v.push_back(t) 在v 的尾端添加元素 t
- v[ n ] 返回第n 个位置上元素的引用,n从0开始,注意:不能用 v[n] 添加元素
- v1=v2 用v2 中的元素 拷贝替换 v1中的元素,即,v1被v2覆盖了
- v1 = { a, b, c...} 用列表中的元素拷贝覆盖v1 中的元素,C++11特性
- v1==v2 v1和v2元素数量相同且对应位置元素相等
- v1 != v2
- <, <=, >, >= 按字典顺序比较
3.迭代器(iterator)介绍
string 和 容器(container) 都可以通过 自身拥有的 begin() 和 end() 成员获取迭代器。
vector<string> vs;
auto b=vs.begin();
auto e=vs.end();
上面的代码里,b 和 e 的类型一样,都是vector<string>::iterator 。
其中b 指向vs 的第一个元素;e指向vs 的尾元素的下一个位置(一个不存在元素的位置)。
end成员返回的迭代器通常称为尾后迭代器(off-the-end iterator) 。
事实上,begin 和 end 返回的具体类型由对象是否为常量决定:
vector<int> vi;
const vector<int> cvi;
auto it1=vi.begin();
auto it2=cvi.begin();
auto it3=vi.cbegin();
上面代码中,it1 的类型是vector<int>::iterator ,it2 和 it3 的类型相同vector<int>::const_iterator 。
cbegin 和 cend 是C++11特性。
迭代器的运算符:
- *iter 返回迭代器iter 所指元素的引用
- iter->mem 解引用iter 并获取该元素(对象)的mem 成员,等价与 (*iter).mem
- ++iter
- --iter
- iter1 == iter2 判断两个迭代器是否相等,相等返回true
- iter1 != iter2
注:如果一个vector 没有元素,那么begin 和 end 成员返回的结果是相等的。
迭代器运算:
- iter+n 迭代器加上一个整数值后,迭代器指示的位置朝着end 方向移动n 。结果指示容器内的一个元素,或指示容器尾元素的下一个位置
- iter-n
- iter+=n
- iter-=n
- iter1-iter2 结果是两个迭代器之间的距离
- >, >=, <, <= 越靠近end ,迭代器的值就越大
//计算得到最接近vi 中间元素的一个迭代器
auto mid = vi.begin() + vi.size()/2 ;
References:
[1] C++ Primer 中文版 (第5版)