C++11:基于C++98的语法更新

目录

一、简介

二、统一的列表初始化方式

2.1{}初始化

2.2std::initializer_list

2.3vector对initializer_list的应用

2.4map对initializer_list的应用

  三、auto

四、decltype

五、STL新容器


一、简介

在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增加的语法特性非常多,本文主要讲解实际中比较实用的语法。

二、统一的列表初始化方式

2.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;
};
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] { 0 };
	return 0;
}

创建对象时也可以使用列表初始化方式调用构造函数初始化。

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 构造
	Date d1(2024, 4, 1); // old style

	// C++11支持的列表初始化,这里会调用构造函数初始化
	Date d2{ 2022, 4, 2 };
	Date d3 = { 2024, 4, 3 };
    Date* darr1 = new Date[3]{d1,d2,d3};
	Date* darr2 = new Date[3]{ { 2024, 3, 23 } ,{ 2024, 3, 23 } ,{ 2024, 3, 23 } };

	Date* darr3 = new Date(2023,3,34);
	Date* darr4 = new Date{ 2023, 3, 34 };
	return 0;
}

温馨提示:虽然这种方式使得初始化朝着大一统的方向发展,但是博主本人依然觉得使用起来及其的别扭和不舒适,加上很多早期代码或编译器不支持这种方式,博主个人建议还是按照原来的习惯将=加上,以免出现意料之外的情况发生。 

2.2std::initializer_list

而相比于我们自己定的日期类,vector定义了一个v1以后为什么可以不断往内部插入数据呢?

因为vector支持了initializer_list

2.3vector对initializer_list的应用

 

如果给auto il 赋值一个{}这时就会认定为这个类型为initializer_list,这个容器不实际存储数据,只是一个临时的数组,此临时数组的生命周期和initializer_list对象的生存周期相同。底层用了一个临时数组将它存起来,本质上是放到了常量区 ,里面通过两个指针,一个begin()指向数组的开头一个指针end()指向数组的结尾。验证如下:

 所以这里是一个initializer_list的构造,可以传任意个数的对象,所以date调用构造是优化后的结果vector也是构造加拷贝构造调用initializer_list的构造,优化后为直接调用构造。

下图则为直接构造 。

同样的,map也支持 initializer_list的构造。

 而dict1就是先将kv1,kv2两个pair传给map中的 initializer_list,变成 initializer_list<pair<const string,string>>的类型


2.4map对initializer_list的应用

而第二个直接在初始化时显示的去写,而第二个之所以可以通过编译,得益于pair的拷贝构造函数,如果直接将“sort”和“排序”传给pair走构造则是const char*类型的,我们将其展开就是如下图的效果编译器依然可以通过,因为pair的拷贝构造重载了一个类模板,并不强制要求传过来的pair必须和当前的pair是同类型,可以看到其中一个拷贝构造的参数为pair类型的引用。

 实现方式如下图所示: 使用了函数模板的方式来进行拷贝构造,可用性非常强。

  三、auto

auto不言而喻,在之前学习c++时就已经了解过了。

在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;
}

c++11之后的版本中auto还可以用作返回值,但博主并不推荐使用auto作为返回值,因为这样在后期回看代码时会造成非常大的阻碍。至少博主不会这样进行使用。

注意:提到auto好多同学都会想到python,认为python慢的原因和auto语法有关,实际上并不是这样,它慢的原因是因为python不编译,它是边编译边运行,它不像c++/c一样先编译好后在运行。

四、decltype

int main()
{
	const int x = 1;
	double y = 2.2;

	cout << typeid(x).name() << endl;
	cout << typeid(string).name() << endl;

	decltype(x) z = 1;
	cout << typeid(z).name() << endl;

	const int* p1 = &x;
	cout << typeid(p1).name() << endl;
	decltype(p1) p2 = nullptr;
	cout << typeid(p2).name() << endl;

	auto ret = func1();
	// 假设要用vector存func1的数据
	vector<decltype(ret)> v;

	return 0;
}


 

它和typeid有些许相同,typeid可以帮助我们去打印类型。可以将底层原生的类可以打出来。

关键字decltype将变量的类型声明为表达式指定的类型。可以在定义对象时进行使用,让编译器去进行推导。

这个z则会定义为int 它会自动去掉1作为常量所带的那个const,而p1则不会去掉const,因为const修饰的是p1所指向的内容而不是p1本身,而还有一种说法将其成为顶层const和底层const,底层修饰的是其所指向的内容,顶层修饰的是变量自身。

 举例:假设一个函数返回一个auto类型,我们就可以用decltype进行实例化推导。

五、STL新容器

大部分在之前博客中已经介绍过了 。

forward_list则是单链表又是一个让博主想吐槽的点,没什么用,不支持双向迭代器,insert只能在当前位置之后去插入,因为没有prev所以不能头插。

 array静态数组,有栈溢出的风险。

  • 39
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

C+五条

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值