目录
一、C++11发展史:
二、列表初始化:
1、初始化:
2、initializer_list函数:
三、声明:
1、auto自动识别类型:
2、decltype:
3、nullptr:
四、范围for:
五、STL中的变化:
一、C++11发展史:
- C++98(1998年):在1998年,C++的第一个国际标准C++98正式发布,标志着C++的正式成熟和广泛应用,这是C++标准的第一个版本,绝大多数编译器都支持,得到了国际标准化组织(ISO)和美国标准化协会的认可,以模版的方式重写了C++标准库,引入了STL(标准模版库)。
- C++03(2003年):这是C++标准的一个重大修订,主要增强了语言的稳定性和兼容性。C++03修复了一些C++98标准中的错误和漏洞。
- C++11(2011年):C++11是一次革命性的更新,为C++引入了大量的新特性和功能。这些新特性包括智能指针、Lambda表达式、范围for循环、右值引用和移动语义、变长参数模板等。C++11使得C++在现代编程中更加灵活、高效和易于使用。
- C++14(2014年):C++14是C++11的一个小幅度修订,主要关注于提升语言的可用性和一致性。C++14引入了一些新的语法特性和库扩展,如泛型lambda表达式,auto的返回类型推导等。
- C++17(2017年):C++17进一步增强了C++的功能和表达能力。这次更新引入了if constexpr、结构化绑定、折叠表达式等语法特性,同时改进了标准库中的多个组件,如string、filesystem等。
- C++20(2020年):C++20是C++历史上的又一个重要里程碑。这次更新引入了一系列新特性和改进,如协程(Coroutines)、概念(Concepts)、模块化(Modules)等。
ok,那么接下来对C++11里面的常用语法进行列举:
二、列表初始化:
1、初始化:
首先要知道,C++ 中的内置类型如int,double等都已经预先配备了构造函数,用于初始化这些类型的变量。
在C++98中也允许使用 花括号{} 对数组 或者 结构体元素 进行统一的列表初始值设定。
C++11扩大了用大括号括起的列表(初始化列表)的使用范围,使其可用于所有的内置类型和自定义的类型。
使用初始化列表时,可添加等号=,也可不添加。
int main()
{int arr1[] = { 1, 2, 3, 4, 5 };for (size_t i = 0; i < sizeof(arr1) / sizeof(arr1[0]); i++){cout << arr1[i] << " ";}cout << endl;int arr2[5] = { 0 };Point p = { 1, 2 };cout << p._x <<" "<<p._y << endl;cout << endl;return 0;
}
// 日期类
class Date
{
public:Date(int d, int m, int y):_day(d), _month(m), _year(y){}private:int _day;int _month;int _year;
};int main()
{int x1 = { 1 }; //可添加等号int x2{ 2 }; //可不添加等号//使用大括号对数组元素进行初始化int array1[]{ 1, 2, 3, 4, 5 }; //可不添加等号int array2[5]{ 0 }; //可不添加等号//使用大括号对结构体元素进行初始化,本质都是调用构造函数Point p1 = { 1, 2 }; //可不添加等号,多参数构造函数隐式类型转换Point p2{ 1, 2 }; //C++11中列表初始化也可以用于new表达式中//int* p3 = new int[4] = { 0 };//不可添加等号int* p3 = new int[4] {0}; int* p4 = new int[4] {1, 2, 3, 4}; //一般调用构造函数创建对象的方式Date d1(1, 2, 3);//C++11支持的列表初始化,这里也会调用构造函数初始化Date d2 = { 2,3,4 };Date d3{ 3,4,5 };return 0;
}
2、initializer_list函数:
这是C++11中新加的,在里面只实现了如下,构造,size,迭代器的功能。
这个是在C++11中的新增的构造函数重载,只要重载了initializer_list函数就能够进行列表初始化
有了这个构造函数就可以对容器进行列表初始化了:
v1这个实际上就是编译器先将{1,2,3,4,5,6,7,8,9}进行类型识别为initializer_list类型,然后再通过C++11新增的构造函数重载。
三、声明:
1、auto自动识别类型:
首先要知道typeid这个关键字,这是一个操作符,类似于sizeof。
运行时获知变量类型名称,typeid(变量).name()
但是这个获得的变量只能看不能用:
如下,只可以打印出来看看:
而auto的作用常常与那种要写特别长的类型,或者是范围for中(这里可就用typeid来打印出来看看)
注意:
1、auto的使用必须在右边要有赋值的,也就是在右边的变量要可知类型变量
2、auto不能直接定义变量。
2、decltype:
关键字decltype将变量的类型声明为表达式指定的类型
如下就是decltype的些许用法,与auto不同的是declype可以不用实例化,只是定义一个变量也可以。
template<class T1, class T2>
void F(T1 t1, T2 t2)
{decltype(t1*t2) ret;cout << typeid(ret).name() << endl;
}
int main()
{const int x = 1;double y = 2.2;decltype(x*y) ret; //ret的类型是doubledecltype(&x) p;//p的类型是int*cout << typeid(ret).name() << endl;cout << typeid(p).name() << endl;F(1, 'a');return 0;
}
decltype还可以进行模版传参,但是auto不可以
decltype可以推导出参数的类型并且进行传递。
vector<decltype(it)> v1;
3、nullptr:
由于C++中NULL被定义成字面量0,这样就可能回带来一些问题,因为0既能指针常量,又能表示整形常量。所以出于清晰和安全的角度考虑,C++11中新增了nullptr,用于表示空指针。
void Func(int x)
{cout << "Func(int x)" << endl;
}void Func(int* p)
{cout << "Func(int* x)" << endl;
}int main()
{int* p = NULL; // int* p = 0;Func(NULL); // Func(0);Func(nullptr);return 0;
}
在如上所示代码中,用NULL传参调用Func函数,本来想的是会走下面的,但是因为C++中NULL被定义成字面量0,所以就会走上面的,所以C++就加了nullptr作为实实在在的空指针。
四、范围for:
这个是C++中的“语法糖”,在遍历的时候就很方便。
int main()
{cout << "遍历vector" << endl;vector<int> v = { 1,2,3,4,5 };for (auto e : v){cout << e << " ";}cout << endl;vector<int>::iterator it = v.begin();while (it != v.end()){cout << *it << " ";it++;}cout << endl;cout << "遍历map" << endl;map<int, int> m = { {1,1},{2,2},make_pair(3,3) };for (auto e : m){cout << e.first << ":" << e.second << endl;}cout << endl;map<int, int>::iterator mit = m.begin();while (mit != m.end()){cout << (*mit).first << ":" << (*mit).second << endl;mit++;}return 0;
}
如上就是对容器进行遍历,范围for的底层实际上就是迭代器的实现的,只要容器支持迭代器就可以使用范围for,通过上述代码也可以看到,写范围for的遍历比写迭代器的遍历的代码量要少得多,所以在日常使用中也多推荐使用范围for。
注意:
范围for中获取的值,默认是不可被修改的,如果想要修改,需要使用引用类型获取值:
int main()
{vector<int> v = { 1,2,3,4,5 };cout << "当未加引用后进行e++操作并不会使数组进行改变" << endl;for (auto e : v){cout << e << " ";e++;}cout << endl;for (auto e : v){cout << e << " ";}cout << endl;cout << "当加引用后进行e++操作并会使数组进行改变" << endl;for (auto& e : v){cout << e << " ";e++;}cout << endl;for (auto e : v){cout << e << " ";}return 0;
}
五、STL中的变化:
如上,红框框中就是STL中新增的容器,unordered_map和unordered_set就是新增的比较不错的容器,并且在之前就已经模拟实现过了。
array这个对标的是静态数组
int main()
{int a1[10];array<int, 10> a2;cout << sizeof(a1) << endl;cout << sizeof(a2) << endl;cout << sizeof(array<int, 20>) << endl;return 0;
}
但是vector基本可以代替这个,并且vector里面还支持迭代器,扩容,插入删除等等。
所以array用的比较少。
forward_list这个是单链表
传统的list是一个双向链表,这个新加的是一个单向链表,只支持头插头删,不支持尾插尾删,因为单链表在进行尾插尾删时需要先找尾,时间复杂度为O(N)。
forward_list提供的插入函数叫做insert_after,也就是在指定元素的后面插入一个元素,这样的是因为比较方便不用找前一个元素,这样效率不会很低。
forward_list提供的删除函数叫做erase_after,也就是删除指定元素后面的一个元素,和insert_after差不多,如果删除前一个效率不行。
总的来说:
forward_list毕竟比list少个指针,所以这个其实就是时间换空间的,但是如今都不是很缺空间,在日常中用的比较少。