目录
C++11 简介
在2003年C++标准委员会曾经提交了一份技术勘误表(简称TC1),使得C++03这个名字已经取代了C++98称为C++11之前的最新C++标准名称。不过由于C++03(TC1)主要是对C++98标准中的漏洞进行修复,语言的核心部分则没有改动,因此人们习惯性的把两个标准合并称为C++98/03标准。
从C++0x到C++11,C++标准10年磨一剑,第二个真正意义上的标准珊珊来迟。相比于C++98/03,C++11则带来了数量可观的变化,其中包含了约140个新特性,以及对C++03标准中约600个缺陷的修正,这使得C++11更像是从C++98/03中孕育出的一种新语言。相比较而言,C++11能更好地用于系统开发和库开发、语法更加泛华和简单化、更加稳定和安全,不仅功能更强大,而且能提升程序员的开发效率,公司实际项目开发中也用得比较多,所以我们要作为一个重点去学习。C++11增加的语法特性非常篇幅非常多,我们这里没办法一 一讲解,所以本节主要讲解实际中比较实用的语法。
想查看 C++11 其他语法的特性,可以去官网进行查询:
C++11 - cppreference.comhttps://en.cppreference.com/w/cpp/11https://en.cppreference.com/w/cpp/11
小故事:
1998年是C++标准委员会成立的第一年,本来计划以后每5年视实际需要更新一次标准,C++国际标准委员会在研究C++ 03的下一个版本的时候,一开始计划是2007年发布,所以最初这个标准叫C++ 07。但是到06年的时候,官方觉得2007年肯定完不成C++ 07,而且官方觉得2008年可能也
完不成。最后干脆叫C++ 0x。x的意思是不知道到底能在07还是08还是09年完成。结果2010年的时候也没完成,最后在2011年终于完成了C++标准。所以最终定名为C++11。
统一的列表初始化
{}初始化
在C++98中,标准允许使用花括号 {} 对数组或者结构体元素进行统一的列表初始值设定
struct Point
{
int _x;
int _y;
};
int main()
{
int array1[] = { 1, 2, 3, 4, 5 };
int array2[5] = { 0 };
Point p = { 1, 2 };
return 0;
}
C++11扩大了用大括号括起的列表(初始化列表)的使用范围,使其可用于所有的内置类型和用户自定义的类型,使用初始化列表时,可添加等号(=),也可不添加
class Point {
public:
Point(int x = 0,int y=0)
:_x(x)
,_y(y)
{}
private:
int _x;
int _y;
};
int main() {
// C++11 花括号列表初始化
int x1 = 1;
int x2{ 1 };
vector<int> v1{ 1,2,3,4,5 };
vector<int> v2 = { 1,2,3,4,5 };
map<string, int> m1{ {"苹果",1},{"西瓜",2} ,{"火龙果",3} };
map<string, int> m2={ {"苹果",1},{"西瓜",2} ,{"火龙果",3} };
m1.insert(make_pair("x", 4));
m1.insert(pair<string, int>("h", 5));
int* p4 = new int[10] { 1, 2, 3, 4 };//c++11支持这样初始化 //c++98不支持new时初始化
Point* p5 = new Point[2]{ {1, 1}, {2, 2} };
// 自定义类型
// 这里会调用构造函数初始化
Point p1(1, 2);
Point p2{1, 2};
Point p3 = { 1, 2 };
}
std::initializer_list
C++11中新增了initializer_list容器,std::initializer_list的介绍文档:
auto il1 = { 1,2,3 };
initializer_list<int> il2 = { 1,2,3 };
initializer_list本质就是一个 {} 括起来的列表, 注:typeid(变量名).name 可用于获取变量的类型名称
std::initializer_list使用场景:
std::initializer_list 一般是作为构造函数的参数,C++11对 STL中的不少容器就增加 std::initializer_list作为参数的构造函数,这样初始化容器对象就更方便了,这样就可以让其他容器支持列表初始化的。也可以作为operator=的参数,这样就可以用大括号赋值
容器是如何支持这种花括号里列表初始化的呢?
vector(initializer_list<T> l)
:_capacity(l.size()),_size(O)
{
_array = new T[_capacity];
for (auto e : l)
_array[_size++] = e;
}
//其他容器也类似
容器支持花括号列表初始化,本质是增加一个initializer_list的构造函数
initializer_list可以接收{}列表
声明
c++11提供了多种简化声明的方式,尤其是在使用模板时。
auto
在C++98中auto是一个存储类型的说明符,表明变量是局部自动存储类型,但是局部域中定义局部的变量默认就是自动存储类型,所以auto就没什么价值了。C++11中废弃auto原来的用法,将其用于实现自动类型推断。这样要求必须进行显示初始化,让编译器将定义对象的类型设置为初始化值的类型。
//auto 不能当形参
auto func(int e) {
std::map<std::string, std::string> dict = { {"insert","插入"},{"sort","排序"} };
return dict; }
int main() {
std::map<std::string, std::string> dict = { {"insert","插入"},{"sort","排序"} };
std::map<std::string, std::string>::iterator it1 = dict.begin();
auto it2 = dict.begin();
// 范围for 除了STL的容器,数组也可以
// 最好给&和const,可以减少拷贝 提高效率
//for (auto e : dict) {
for (const auto& e : dict) {
cout << e.first << ":" << e.second << endl;
}
for ( std::pair<const std::string, std::string>& e : dict) {
cout << e.first << ":" << e.second << endl;
}
cout << func(1)["insert"];
//无法推导出类型
//auto dict2 = { {"insert","插入"},{"sort","排序"} };
//cout << typeid(dict2).name() << endl;
return 0;
}
decltype
关键字decltype将变量的类型声明为表达式指定的类型。
如果我们不知道某一个变量或者表达式的类型,我们可以通过 typid(p).name 来拿到类型的字符串。但是我们却无法真正取到“类型”,此时我们就需要使用 decltype(推导类型)。
template<class T1,class T2>
void F(T1 t1, T2 t2) {
//推导并保存 t1*t2的类型
decltype(t1 * t2)ret = t1 * t2;
vector<decltype(t1, t2)>v;
cout << typeid(ret).name << endl;
}
int main()
{
//decltype 推导类型
//我们不可以 typeid(p) i
auto pf = strcpy;
decltype(pf)pf1;
vector<decltype(pf)>v;
}
nullptr
由于C++中NULL被定义成字面量0,这样就可能回带来一些问题,因为0既能指针常量,又能表示
整形常量。所以出于清晰和安全的角度考虑,C++11中新增了nullptr,用于表示空指针。
C++11中STL的一些变化
C++11中新增了四个容器,分别是array、forward_list(单链表)、unordered_map和unordered_set
容器中的一些新方法
C++11为每个容器都增加了一些新方法,比如:
- 提供了一个以 initializer_list 作为参数的构造函数,用于支持列表初始化。
- 提供了cbegin和 cend方法,用于返回 const迭代器。但是实际意义不大,因为 begin和 end也是可以返回 const迭代器的,这些都是属于锦上添花的操作
- 提供了emplace系列方法,并在容器原有插入方法的基础上重载了一个右值引用版本的插入函数,用于提高向容器中插入元素的效率
C++98容器
string/vector/list/deque/map/set/bitset(位图) + stack/queue/priority_queue
C++11新容器
array(定长数组):用的很少,缺点:定长+存储数据的空间在栈上,栈的空间本来就很少
forword_list(单链表):用的很少,缺点:不支持尾插尾删+insert数据也是在当前位置的后面
unordered_map/unordered_set:推荐使用,效率高于map/set