文章目录
一、统一的列表初始化
1.1 { }花括号初始化
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扩大了用大括号括起的列表(初始化列表)的使用范围,使其可用于所有的内置类型和用户自定义的类型,使用初始化列表时,可添加等号(=),也可不添加。
struct Point
{
int _x;
int _y;
Point(int x, int y)
:_x(x)
,_y(y)
{
cout << "Point(int x, int y)" << endl;
}
};
int main()
{
// 等号= 可以省
int x1 = 1;
int x2{ 2 };
int array1[]{ 1, 2, 3, 4, 5 };
int array2[5]{ 0 };
Point p{ 1, 2 };
// C++11中列表初始化也可以适用于new表达式中
int* pa = new int[4]{ 1,2,3,4 };
Point* ptr = new Point[2]{ {2,2},{3,3} };
return 0;
}
1.2 explicit关键字
防止隐式类型转换
我们之前学习类和对象时知道,单参的构造函数具有隐式类型转换的作用,但是我们有些时候,不想让他进行隐式类型转化。
// 单参数
class A
{
private:
int _a;
public:
explicit A(int a)
:_a(a)
{}
};
int main()
{
A a1(1);
A a2 = { 2 };// 这里就是 2转换成一个int对象,再拷贝构造给a2对象
return 0;
}
1.3 std::initializer_list
int main()
{
// C++98
vector<int> v1;
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
// C++11
vector<int> v2 = { 1,2,3,4,5,6,7 };
initializer_list<int> il = { 1,2,3,4,5,6,7 };
return 0;
}
支持的原理:新增了一个构造函数(list,map,set等等都新增了这个构造函数,原理也是一样的)
initializer_list
在C++里面是一个容器,把一个花括号及其里面的内容(看做一个整体)传给il
对象,这个il
对象的类型就是initializer_list
模拟实现:
vector(initializer_list<T> ilt)
{
typename initializer_list<T>::iterator it = ilt.begin();
while (it!=ilt.end())
{
ilt.push_back(*it);
++it;
}
}
二、声明
2.1 auto
在C++98中auto是一个存储类型的说明符,表明变量是局部自动存储类型,但是局部域中定义局部的变量默认就是自动存储类型,所以auto就没什么价值了。C++11中废弃auto原来的用法,将其用于实现自动类型推断。这样要求必须进行显示初始化,让编译器将定义对象的类型设置为初始化值的类型。
int main()
{
int i = 10;
auto p = &i;
auto pf = strcpy;
cout << typeid(p).name() << endl;
cout << typeid(pf).name() << endl;
map<string, string> dict = { {"sort", "排序"}, {"insert", "插入"} };
//map<string, string>::iterator it = dict.begin();
auto it = dict.begin();
return 0;
}
2.2 decltype
关键字decltype将变量的类型声明为表达式指定的类型。
int main()
{
const int x = 1;
double y = 2.2;
decltype(x) z = 1; // 拿x的类型来定义新的变量
decltype(x * y) ret;// ret的类型是double
decltype(&x) p; // p的类型是int*
return 0;
}
实用场景:
在定义模板的时候特别有用,因为只有等到模板被实例化时才能确定类型
int func(int a)
{
cout << "int func(int a)" << endl;
return a;
}
int main()
{
int(*pfunc1)(int) = func; //函数指针
auto pfunc2 = func;
decltype(&func) pfunc3;
// 只能用decltype的场景——模板
vector<decltype(func)> v;
//vector<auto> v;报错
return 0;
}
2.3 nullptr
空指针是不会指向有效数据的指针。以前C++在源代码中使用0表示这种指针,但是内部表示可能不同。这带来了一些问题,因为这使得0既可以表示指针常量,又可以表示整型常量。所以出于清晰和安全的角度考虑,C++11中新增了nullptr
,用于表示空指针。
#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
#endif
三、STL中的一些变化
3.1 新增容器
这几个新增容器中,实际最有用的是unordered_map
和unordered_set
。
vector与array的区别
array的价值:
1、支持迭代器,更好兼容STL
2、对于越界的检查
int a[10];
a[14] = 0; //抽查 *(a+14)=0;
array[14] = 0; //必查 array.operator[](14)=0;
//调用assert,断言检查
3.2 新增一些好用高效的接口
比如:初始化列表、右值引用版本的接口函数、移动构造、移动赋值