目录
C++11简介
统一的列表初始化
{}初始化
std::initializer_list
文档介绍
std::initializer_list的类型
使用场景
initializer_list接口函数模拟实现
auto与decltype
nullptr
范围for
STL的变化
新容器
新方法
新函数
C++11简介
1.在2003年C++标准委员会曾经提交了一份技术勘误表(简称TC1),使得C++03这个名字已经取代了C++98称为C++11之前的最新C++标准名称不过由于C++03(TC1)主要是对C++98标准中的漏洞进行修复,语言的核心部分则没有改动,因此人们习惯性的把两个标准合并称为C++98/03标准。2.相比于C++98/03,C++11则带来了数量可观的变化,其中包含了约140个新特性,以及对C++03标准中约600个缺陷的修正,这使得C++11更像是从C++98/03中孕育出的一种新语言。相比较而言,C++11能更好地用于系统开发和库开发、语法更加泛华和简单化、更加稳定和安全,不仅功能更强大,而且能提升程序员的开发效率,公司实际项目开发中也用得比较多,所以我们要作为一个重点去学习。
统一的列表初始化
{}初始化
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;
}
struct Point
{
int _x;
int _y;
};
int main()
{
int x1 = 1;
int x2{ 2 };
int array1[]{ 1, 2, 3, 4, 5 };
int array2[5]{ 0 };
Point p{ 1, 2 };
//也适用于new表达式
int* pa = new int[4]{ 0 };
return 0;
}
int main()
{
vector<int> v1;
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
vector<int> v2 = { 1, 2, 3, 4 };
list<int> lt1 = { 1, 2, 3, 4, 5 };
pair<string, string> kv("left", "左边");
pair<string, string> kv1{ "left", "左边" };
map<string, string> dict = { { "insert", "插入" }, kv, make_pair("list", "列表") };
v2 = { 10, 20, 30 };
initializer_list<int> ilt = { 1, 2, 3, 4, 5, 6, 7 };
return 0;
}
支持隐式类型的转换
//单参数
class A
{
public:
//explicit A(int a)
// :_a(a)
//{}
A(int a)
:_a(a)
{}
private:
int _a;
};
//多参数
struct Point
{
int _x;
int _y;
Point(int x, int y)
:_x(x)
, _y(y)
{
cout << "Point(int x, int y)" << endl;
}
//explicit Point(int x, int y)
// :_x(x)
// , _y(y)
//{
// cout << "Point(int x, int y)" << endl;
//}
};
int main()
{
//单参数构造函数支持隐式类型转换
A aa1(1);
A aa2 = 2;
string s1("hello");
string s2 = "world";
vector<string> v;
v.push_back(s1);
v.push_back("world");
//C++11
Point p1(1, 2);
//多参数构造函数,支持隐式类型转换
Point p2 = { 1, 2 };
Point p3{ 1, 2 };
int a = 1;
int b = { 2 };
int c{ 3 };
int array1[]{1, 2, 3, 4, 5};
int array2[5]{ 0 };
int* ptr1 = new int[5]{1, 2, 3};
Point* ptr2 = new Point[2]{{ 1, 1 }, { 2, 2 }};
return 0;
}
std::initializer_list
文档介绍
std::initializer_list的类型
int main()
{
// the type of il is an initializer_list
auto il = { 10, 20, 30 };
cout << typeid(il).name() << endl;
return 0;
}
使用场景:
std::initializer_list一般是作为构造函数的参数,C++11对STL中的不少容器就增加了std::initializer_list作为参数的构造函数,这样初始化容器对象就更方便了。也可以作为operator= 的参数,这样就可以用大括号赋值。
int main()
{
vector<int> v = { 1, 2, 3, 4 };
list<int> lt = { 1, 2 };
// 这里{"sort", "排序"}会先初始化构造一个pair对象
map<string, string> dict = { {"sort", "排序"}, {"insert", "插入"} };
// 使用大括号对容器赋值
v = {10, 20, 30};
return 0;
}
这些容器之所以能够支持这样子的列表初始化实际上是因为容器的成员函数当中增加了一个以initializer_list为参数的构造函数
实际上就是先通过initializer_list构造出来一个列表,然后将这个列表中的所有元素拷贝到要构造的容器当中
initializer_list接口函数模拟实现
vector容器中模拟这个构造函数
vector(initializer_list<T> il)
{
_start = new T[il.size()];
_finish = _start;
_endofstorage = _start + il.size();
for (auto x : il)
{
push_back(e);
}
}
如果我们要实现等于号操作支持列表初始化也可以进行一个函数重载
vector<T>& operator=(initializer_list<T> il)
{
vector<T> tmp(il);
std::swap(_start, tmp._start);
std::swap(_finish, tmp._finish);
std::swap(_endofstorage, tmp._endofstorage);
return *this;
}
假如我们使用迭代器遍历,由于使用了模板参数,所以我们在声明类型的时候要加上typename 告知编译器这是一个类型
auto与decltype
在C++11中 auto关键字的作用是自动推导类型
map<int, string> m;
map<int, string>::iterator it = m.begin();
auto it = m.begin();
int main()
{
const int x = 1;
double y = 2.2;
//cout << typeid(x).name() << endl;
decltype(x) z = 2;
decltype(x * y) ret; //ret的类型是double
decltype(&x) p; //p的类型是int*
int(*pfunc1)(int) = func;
auto pfunc2 = func;
decltype(pfunc2) pfunc3 = func;
decltype(&func) pfunc4 = func;
map<string, string> dict = { { "sort", "排序" }, { "insert", "插入" } };
auto it = dict.begin();
//decltype的一个使用场景
//decltype(it) copyIt = it;
auto copyIt = it;
vector<decltype(it)> v;
v.push_back(it);
return 0;
}
nullptr
在C语言中NULL 即空指针 被定义成了0 但是这在一些情况下可能会带来一些问题
比如下面代码:
void f(int arg)
{
cout << "void f(int arg)" << endl;
}
void f(int* arg)
{
cout << "void f(int* arg)" << endl;
}
int main()
{
f(NULL);
return 0;
}
当我们向函数参数中传递一个空指针的时候实际上我们是想要调用第二个函数,可是结果却不符合我们的预期,于是C++11的标准中引入了nullptr来代表空指针,使得我们写的代码更加的严谨
#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
#endif
范围for
vector<int> v;
v.push_back(2);
v.push_back(5);
v.push_back(4);
v.push_back(7);
for (auto x : v)
{
cout << x << endl;
}
- auto关键字可以自动推导类型,当然我们也可以手动写出类型
- x为变量名,它代表的是容器中的每个数据
- 变量名和容器名之间用冒号隔开
STL的变化
新容器
array
int main()
{
int a1[10];
array<int, 10> a2;
cout << sizeof(a2) << endl;
//支持迭代器
//对于越界的检查
a1[14] = 0; // *(a1 + 14) = 0;
//a2[14] = 0; // a2.operator[](14) = 0;
return 0;
}
array和普通数组的对比
相同点:
它和普通数组一样支持通过下标访问操作符[]来访问数据,支持范围for,并且创建后的数组大小不可改变
不同点:
它使用一个类对于array容器进行了封装,对于数组边界的检查更加严格了,如果使用下标访问操作符越界会出现断言检查,如果使用 at 成员函数访问会抛出异常
forward_list
它的本质是一个单链表
1.只支持头插头删,因为单链表的尾插尾删时间复杂度是O(N),而头插头删的时间复杂度则是 O(1)
2.forward_list容器提供的插入函数叫做insert_after,是在指定元素的后面插入一个元素
3.forward_list容器提供的删除函数叫做erase_after,是在指定元素的后面删除一个元素
unordered_map和unordered_set
可以参考我之前的博客
unordered_map和unordered_set的容器使用
新方法
C++容器中提供了一些新方法
1.提供了一个以initializer_list作为参数的构造函数,用于支持列表初始化
2.提供了cbegin和cend方法,用于返回const迭代器
3.提供了emplace系列方法,并在容器原有插入方法的基础上重载了一个右值引用版本的插入函数 用于提高向容器中插入元素的效率
新函数
to_string()