1. 统一的列表初始化
1.1 c++中{}初始化
#include<iostream>
using namespace std;
// 点坐标的类
struct Point
{
int _x;
int _y;
};
// 日期类
class Date
{
public:
Date(int year, int month, int day)
:_year(year)
, _month(month)
, _day(day)
{
cout << "Date(int year, int month, int day)" << endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
// c++98的用法
Point p1 = { 1, 2 };
// c++11的用法
Point p2{ 2, 2 };
// c++98的用法
int array1[] = { 1, 2, 3, 4, 5 };
// c++11的用法
int array2[]{ 1, 2, 3, 4, 5 };
// c++98的用法
int x1 = 1;
// c++11的用法 建议不要这么用,能看懂就可以,我们自己别玩
int x2 = { 1 };
int x3{ 1 };
// c++98的用法
int* p3 = new int[10];
// c++11的用法
int* p4 = new int[10]{1, 2, 3, 4};
Point* p5 = new Point[2]{{ 1, 1 }, { 2, 2 }};
// c++98的用法
Date d1(1, 1, 1);
// c++11的用法
Date d2{ 1, 1, 1 };
return 0;
}
1.2 std::initializer_list
std::initializer_list是什么类型:
initializer n.初始化器
#include<iostream>
#include <vector>
#include <list>
#include <map>
using namespace std;
class Date
{
public:
Date(int year, int month, int day)
:_year(year)
, _month(month)
, _day(day)
{
cout << "Date(int year, int month, int day)" << endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
vector<int> v1 = { 1, 2, 3, 4 };
vector<int> v2{ 1, 2, 3, 4,6,7,7 };
list<int> lt = { 1, 2 };
//这里的{}是在调用构造函数
Date d1{ 1, 1, 1 };
// 通过打印的结果,我们可以判断出 il的类型为class std::initializer_list<int>
// 也就是initializer_list
// initializer_list我们也可以理解为是一个容器,底层是一个常量数组
// 这里的{}是将其内部的数据,识别成为一个常量数组
auto il = { 1, 2, 3, 4, 5 };
cout << typeid(il).name() << endl;
// { 1, 1, 1 }, { 2, 2, 2 }, { 3, 3, 3 } 是调用3次构造函数,来构造3个匿名的Data对象
vector<Date> v3 = { { 1, 1, 1 }, { 2, 2, 2 }, { 3, 3, 3 } };
// { "字符串", "string" }, { "排序", "sort" } 是调用两次map的构造函数,来构造两个map的匿名对象
map<string, string> dict = { { "字符串", "string" }, { "排序", "sort" } };
return 0;
}
- 打印结果如下:
Date(int year, int month, int day)
class std::initializer_list<int>
Date(int year, int month, int day)
Date(int year, int month, int day)
Date(int year, int month, int day)
让模拟实现的vector也支持{}初始化和赋值
// 只需要在vector的类里面添加vector(initializer_list<T> il)的构造就可以了
// 就可以支持vector<int> v1 = { 1, 2, 3, 4 };
// 具体的实现如下所示,我们也可以自己粘贴下面的代码试着去运行一下
#include<iostream>
using namespace std;
template<class T>
class vector
{
public:
typedef T* iterator;
typedef const T* const_iterator;
iterator begin()
{
return _start;
}
iterator end()
{
return _finish;
}
vector()
:_start(nullptr)
, _finish(nullptr)
, _endofstorage(nullptr)
{}
// 只需要在此处添加对il的构造就可以了
vector(initializer_list<T> il)
:_start(nullptr)
, _finish(nullptr)
, _endofstorage(nullptr)
{
// 使用reserve提前开好所需要的空间
reserve(il.size());
typename initializer_list<T>::iterator it = il.begin();
// 方法一:使用迭代器遍历将il中的数据,依次尾插到vector中
//while (it != end())
//{
// push_back(*it);
// ++it;
//}
// 方法二:使用范围for将il中的数据,依次尾插到vector中
for (auto& e : il)
{
push_back(e);
}
}
~vector()
{
delete[] _start;
_start = _finish = _endofstorage = nullptr;
}
void reserve(size_t n)
{
if (n > capacity())
{
size_t oldSize = size();
T* tmp = new T[n];
if (_start)
{
//memcpy(tmp, _start, sizeof(T)*oldSize);
for (size_t i = 0; i < oldSize; ++i)
{
tmp[i] = _start[i];
}
delete[] _start;
}
_start = tmp;
_finish = tmp + oldSize;
_endofstorage = _start + n;
}
}
size_t size() const
{
return _finish - _start;
}
size_t capacity() const
{
return _endofstorage - _start;
}
void push_back(const T& x)
{
if (_finish == _endofstorage)
{
size_t newCapacity = capacity() == 0 ? 4 : capacity() * 2;
reserve(newCapacity);
}
*_finish = x;
++_finish;
}
private:
iterator _start;
iterator _finish;
iterator _endofstorage;
};
int main()
{
vector<int> v1 = { 1, 2, 3, 4 };
for (auto& e : v1)
{
cout << e << endl;
}
return 0;
}
2.声明
2.1 auto
// 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();
cout << typeid(it).name() << endl;
return 0;
}
2.2 decltype(了解)
关键字decltype将变量的类型声明指定为表达式的类型。
#include <iostream>
#include <typeinfo> // 包含 typeid 所需的头文件
template<class T1, class T2>
void F(T1 t1, T2 t2)
{
// t1 和 t2可能是两个不同类型的变量
// 可以使用decltype推断出t1*t2 之后的类型
// 如int*double,int会发生整型提升,最终的类型为double
// 推断出t1 * t2乘积后的类型
decltype(t1 * t2) ret = t1 * t2;
std::cout << typeid(ret).name() << std::endl; // 输出 ret 的类型名称
std::cout << ret << std::endl; // 输出 ret 的值
}
int main()
{
int x = 0;
std::cout << typeid(x).name() << std::endl;
// decltype 可以传入的x推断出x的类型,并将这个类型作为变量y的类型
decltype(x) y;
F(1, 2);
F(1, 2.2);
return 0;
}
2.3nullptr
由于C++中NULL被定义成字面量0,这样就可能回带来一些问题,因为0既能指针常量,又能表示整形常量。所以出于清晰和安全的角度考虑,C++11中新增了nullptr,用于表示空指针。
#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
#endif
3.STL中一些变化
新容器
用橘色圈起来是C++11中的一些几个新容器,但是实际最有用的是unordered_map
和unordered_se
t。这两个有在单独的博客介绍,其他的大家了解一下即可。
// 简单的了解对array的使用
#include<iostream>
#include<array>
#include<vector>
using namespace std;
int main()
{
// 数组的大小为10,数组元素的类型为int
array<int, 10> a1;
int a2[10];
// 系统对于普通数组的检查是一种抽查,因此这里a2[10] = 3 虽然越界了,但是系统并不会报错
a2[20] = 3;
// 下面是array类型的数组,只要越界了,不管是读还是写,系统都会报错
// 因为array类型的数组,内置了检查机制,只要超过范围就会被检测到
// a1[10] = 1;
// a1[10];
// 但是,我们使用vector也可以达到和array同样的效果
// 内置了检查机制,只要超过范围就会被检测到
// 数组的大小初始化为10,数组元素类型为int,并将10个元素都初始化为0
vector<int> v(10, 0);
v[10];
return 0;
}
=========================================================================================
// forward_list 也就是底层为一个单链表的容器