23.c++11的新特性_1

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的介绍文档:

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_mapunordered_set。这两个有在单独的博客介绍,其他的大家了解一下即可。

image-20230414171110566

// 简单的了解对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 也就是底层为一个单链表的容器
  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值