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增加的语法特性非常篇幅非常多,我们这里没办法一一讲解,所以本节课程主要讲解实际中比较实用的语法。
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 11文档
统一的列表初始化
{}初始化
{}初始化:一切皆可列表初始化。
在C 98中,标准允许使用花括号{}对数组或者结构体元素进行统一的列表初始值设定。比如:
代码语言:javascript复制struct Point
{
int _x;
int _y;
};
int main()
{
// C
int array1[] = { 1, 2, 3, 4, 5 };
int array2[5] = { 0 };
Point p = { 1, 2 };
return 0;
}
C 11扩大了用大括号括起的列表(初始化列表)的使用范围,使其可用于所有的内置类型和用户自定义的类型,使用列表初始化时,可添加等号(=),也可不添加
代码语言:javascript复制class A
{
public:
A(int x,int y)
:_x(x)
,_y(y)
{}
A(int x)
:_x(x)
,_y(x)
{}
private:
int _x;
int _y;
};
int main()
{
int array1[] = { 1, 2, 3, 4, 5 };
int array2[5] = { 0 };
int array[5]{ 0 };
//多参数的隐式类型转换
A a1 = { 2,2 };
A a5{ 2,2 };
//单参数的隐式类型转换
A a2 = 1;
A a3 = { 1 };
//隐式类型转换
const A& a4 = { 2,2 };
return 0;
}
std::initializer_list
std::initializer_list的介绍文档
std::initializer_list
的类型:
内部有两个指针,一个指向开始,一个指向结束:
x自定义类型 = Y类型 -> 隐式类型转换 X(Y mm),X支持Y为参数类型构造就可以
代码语言:javascript复制//vector(<initializer_list<T>> il);
vector<int> v5({ 1,2,3,4,5 });
代码语言:javascript复制int main()
{
vector<int> v1;
vector<int> v2(10, 1);
vector<int> v3 = { 1,2,3,4,5 };
vector<int> v4 = { 10,20,30 };
auto il1 = { 10,20,30 };
initializer_list<int> il2 = { 10,20,30 };
cout << typeid(il1).name() << endl;
cout << typeid(il2).name() << endl;
cout << sizeof(il1) << endl;
//构造
vector<int> v5({ 1,2,3,4,5 });
//1.pair多参数的隐式类型转换 2.initializer_list<pair>的构造
map<string, string> dict = { {"sort", "排序"}, {"insert", "插入"} };
return 0;
}
声明
auto
在C 98中auto是一个存储类型的说明符,表明变量是局部自动存储类型,但是局部域中定义局部的变量默认就是自动存储类型,所以auto就没什么价值了。C 11中废弃auto原来的用法,将其用于实现自动类型腿断。这样要求必须进行显示初始化,让编译器将定义对象的类型设置为初始化值的类型。
x
是对i
的单纯的拷贝,x
不会影响i
:
默认auto
推导的都是类型,但是使用引用,auto&
时,x
是i
的别名:
j
是 i
的引用,任何对 j
的操作都会直接影响 i
,auto
推断 y
的类型为 int
,因为 j
是 int&
(引用),y
是 j
的副本,即 i
的副本。y
的值与 i
相同:
decltype
typeid
可以查看数据类型,单纯的推出一个字符串,表示类型,但是不用用于定义对象:
关键字decltype
将变量的类型声明为表达式指定的类型:
decltype
一般是配合模板传参使用:
template<class T>
class B
{
public:
T* New(int n)
{
return new T[n];
}
};
auto func1()
{
list<int> lt;
auto ret = lt.begin();
return ret;
}
int main()
{
auto ret3 = func1();
B<decltype(ret3)> bb1;
return 0;
}
nullptr
由于C 中NULL被定义成字面量0,这样就可能回带来一些问题,因为0既能指针常量,又能表示整形常量。所以出于清晰和安全的角度考虑,C 11中新增了nullptr,用于表示空指针。
代码语言:javascript复制#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
#endif
STL的变化
新容器
用橘色圈起来是C 11中的一些几个新容器,但是实际最有用的是unordered_map
和
unordered_set
。
容器中的一些新方法
如果我们再细细去看会发现基本每个容器中都增加了一些C 11的方法,但是其实很多都是用得比较少的。 比如提供了cbegin和cend方法返回const迭代器等等,但是实际意义不大,因为begi和end也是可以返回const迭代器的,这些都是属于锦上添花的操作。