C++11语法杂记(更新中)

本文介绍了C++11的一些重要特性,包括default关键字用于强制生成默认成员函数,delete关键字阻止默认函数生成,可变参数模板的使用以及emplace系列的高效插入。还讨论了noexcept和constexpr在异常处理和常量表达式中的作用。
摘要由CSDN通过智能技术生成

在这里插入图片描述

一. delctype

delctype和auto类似,也可以自动识别类型
举例如下:
在这里插入图片描述

与auto不同的是,auto只能用于定义变量类型,而decltype返回的是类型,可以应用到模板

在这里插入图片描述

二. default

C++11可以让我们更好的控制是否生成默认成员函数。如果我们需要某个默认的成员函数,但是因为一些原因,该函数没有默认生成,那么我就可以使用default关键字强制其生成。
比如:我们提供了析构函数,拷贝构造,拷贝赋值重载的任意一个,那么编译器就不会帮我们生成默认的移动构造。此时我们可以使用default关键字,显示指定其生成。

假设我们现在有一个Person类。
我们强制其生成移动构造

Person(Person&&p)=default;

三. delete

C++11也提供我们限制某些默认函数的生成。
在C++98中,是将该函数设置成private。但在C++11中,提供了delete关键字,只需要在该函数声明后加上=delete,编译器就不会生成其默认函数,称=delete修饰的函数为删除函数。
一般一个类不允许修改,就可以使用=delete

STL中就有这样的应用
在这里插入图片描述

同样还是Person类,假如我们不想生成默认拷贝构造

Person(const Person&p)=delete;

四. 可变参数模板

在C语言中,我们有使用过可变参数

在这里插入图片描述
即,我们可以传递多个参数,编译器会自动帮我们识别。

在C++98/03中,类模板和函数模板只能固定数量的模板参数,而在C++11中,可变参数模板可以让我们任意传递数据类型。

基本的可变参数模板时这样的

//Args是一个模板参数包,args是一个函数形参参数包
//声明一个参数包Ags...args,这个参数熬中可以包含0到任意个模板参数
template<class ...Args>
void showList(Args... args)
{
	//我们可以使用sizeof查看当前可变参数包有几个参数
	cout << sizeof...(args) << endl;
}

int main()
{
	showList('x');
	showList('x', 6);
	showList('x', 6, 3.0);
}

运行结果如下:

在这里插入图片描述

而我们要想解析可变参数包,有以下两种方法:

第一种方法

使用一个模板参数,递归逐个接收可变参数包的参数。

代码如下:

void showList()
{
	cout << endl;
}

template<class T,class ...Args>
void showList(const T&val,Args... args)
{
	cout << val << " ";
	showList(args...);
}

int main()
{
	showList('x');
	showList('x', 6);
	showList('x', 6, string("hello world"));
}

我们通过第一个模板参数,将可变参数包的参数逐个取出,知道可变参数包参数个数为0时,会调用最上面的showList,打印换行,并且其作为递归终止的条件

在这里插入图片描述

同时我们还可以获取其参数类型

在这里插入图片描述

可变参数包类型的推导是在编译的时候进行的,和函数模板的实例化一样。

第二种方法

template<class T>
int Print(const T&val)
{
	cout << val << " ";

	return 0;
}

template<class ...Args>
void printList(Args... args)
{
	int arr[] = { Print(args)... };
	cout << endl;
}

int main()
{
	printList('x');
	printList('x', 6);
	printList('x', 6, string("hello world"));
}

在printList中,我们用Print(args)…的返回值初始化arr数组,编译时,需要知道arr数组有多大,所以会解析Print,然后Print每次接收可变参数包的一个参数,有几个参数,就会解析几次。

在这里插入图片描述

而可变参数包在STL中也有使用

在这里插入图片描述
线程的构造函数,就有使用可变参数包,因为传参可能发送拷贝。所以这里使用万能引用,左值,右值都可以接收。

在这里插入图片描述

emplace系列也使用万能引用的可变参数包

五. emplace系列

在STL中,所有的容器都增加了emplace的插入
在这里插入图片描述

接下来我们就来分析一下emplace系列和push系列的差别

在这里插入图片描述

在这里插入图片描述

可以看到,emplace_back使用了可变参数包,push_back有左值引用和右值引用的版本。

简单实现一个string,在其构造,拷贝构造和移动构造部分打印内容,方便展示效果

在这里插入图片描述

首先,我们看到,push_back和emplace_back对于深拷贝的左值和右值效率是一样的。
因为在push_back和emplace_back在类模板中都实例化的是string。

我们再看以下场景

在这里插入图片描述

如果是直接用字符串构造,那么push_back会先调用string的单参构造,构造一个临时对象,然后再移动拷贝
而emplace_back因为是可变参数包,所以推演出的是const char*,这样就会直接去调用单参构造。但是对于深拷贝的类,push_back和emplace_back的效率差别不大,因为push_back就多一个移动拷贝,代价很低。

但是看到这里,相信大家也明白效率差异会出现在浅拷贝的类,如果浅拷贝的类,成员很多,那么按字节拷贝的代价还是很高的。push_back在面对这样传值构造,而不是传类对象构造,需要一次单参数构造,和一次按字节拷贝。而emplace_back只需要单参数构造即可。emplace因为使用可变参数包,所以,只要类有有参构造,那么可变参数包就可以匹配,从而直接构造

总体来说,emplace比push高效在复杂的浅拷贝类。深拷贝相差不大,但push_back的使用场景,emplace_back也可以使用,所以无脑使用emplace是可以的

六. noexcept

七. constexpr

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值