变参模板 (Variadic Template- 使得 emplace 可以接受任意参数,这样就可以适用于任意对象的构建

完美转发 - 使得接收下来的参数 能够原样的传递给对象的构造函数,这带来另一个方便性

先来看看下边的代码,看一下C11标准中提供的变参模板的用法之一:

 1 #include <iostream>
2 #include <vector>
3
4 using namespace std;
5
6 class student
7 {
8 public:
9 student(int age, const char name[64])
10 {
11 this -> age = age;
12 strncpy_s(this->name, sizeof(this->name) - 1, name, sizeof(name));
13 cout << "调用有参构造函数" << endl;
14 }
15
16 student(const student& stud)
17 {
18 this->age = stud.age;
19 strncpy_s(this->name, sizeof(this->name) - 1, stud.name, sizeof(stud.name));
20 cout << "调用拷贝构造函数" << endl;
21 }
22
23 ~student()
24 {
25 cout << "调用析构函数" << endl;
26 }
27
28 private:
29 int age;
30 char name[64];
31
32 };
33
34 int main()
35 {
36 vector<student> vectStud;
37
38 //方法一:
39 //student stud(18, "姓名");
40 //vectStud.push_back(stud);
41
42 //方法二:
43 vectStud.push_back(student(18, "姓名"));
44
45 return 0;
46 }

方法一 与 方法二 的打印结果完全相同:

打印中第一行的有参构造函数是第39行代码调用到的,40行代码将这个对象放置到vector容器中时,会创建一个临时对象进行拷贝。这会造成效能的浪费。

为了解决这个问题C++11中加入了 变参模板 & 完美转发,使得 emplace 可以接受任意参数,这样就可以适用于任意对象的构建,如下代码:

 1 #include <iostream>
2 #include <vector>
3
4 using namespace std;
5
6 class student
7 {
8 public:
9 student(int age, const char name[64])
10 {
11 this -> age = age;
12 strncpy_s(this->name, sizeof(this->name) - 1, name, sizeof(name));
13 cout << "调用有参构造函数" << endl;
14 }
15
16 student(const student& stud)
17 {
18 this->age = stud.age;
19 strncpy_s(this->name, sizeof(this->name) - 1, stud.name, sizeof(stud.name));
20 cout << "调用拷贝构造函数" << endl;
21 }
22
23 ~student()
24 {
25 cout << "调用析构函数" << endl;
26 }
27
28 private:
29 int age;
30 char name[64];
31
32 };
33
34 int main()
35 {
36 vector<student> vectStud;
37
38 //方法一:
39 //student stud(18, "姓名");
40 //vectStud.push_back(stud);
41 //方法二:
42 //vectStud.push_back(student(18, "姓名"));
43
44 //使用 emplace_back
45 vectStud.emplace_back(18, "姓名");
46
47 return 0;
48 }

从打印结果可以看出,使用了 emplace_back 之后可以省略一个零时对象,并且不用进行拷贝构造函数的操作。

emplace_back 也就相当于一个 push_back 的操作

还有一个 emplace ,是在指定位置插入相关数据,类似于 insert,如下代码:

 1 #include <iostream>
2 #include <vector>
3
4 using namespace std;
5
6 class student
7 {
8 public:
9 student(int age, const char name[64])
10 {
11 this -> age = age;
12 strncpy_s(this->name, sizeof(this->name) - 1, name, sizeof(name));
13 cout << "调用有参构造函数" << endl;
14 cout << "姓名:" << this->name << " " << "年龄:" << this->age << endl;
15 }
16
17 student(const student& stud)
18 {
19 this->age = stud.age;
20 strncpy_s(this->name, sizeof(this->name) - 1, stud.name, sizeof(stud.name));
21 cout << "调用拷贝构造函数" << endl;
22 }
23
24 ~student()
25 {
26 cout << "调用析构函数" << endl;
27 }
28
29 private:
30 int age;
31 char name[64];
32 };
33
34 int main()
35 {
36 vector<student> vectStud;
37
38 //方法一:
39 //student stud(18, "姓名");
40 //vectStud.push_back(stud);
41 //方法二:
42 //vectStud.push_back(student(18, "姓名"));
43
44 //使用 emplace_back
45 vectStud.emplace_back(18, "张三");
46
47 //使用 emplace
48 vectStud.emplace(vectStud.begin(), 20, "李四");
49
50 return 0;
51 }

打印结果:

这里有个有趣的现象,第5行出现了一个拷贝构造函数,并且调用了3次析构函数。

这是因为 vector 的存储方式决定的,因为 vector 的存储空间是由元素的多少进行变化的,而我们在第48行的代码中使用了 begin() ,在首位置插入,导致内存空间发生了变化。编译器需要将第一个张三拷贝至李四的前方,然后析构掉。如果前方在插入一个,将会把后两个元素再进行拷贝和析构,以此类推。

不同的编译器,对于 vector 新插入元素的拷贝和析构的顺序有可能不同,即使是 VS2015 与 VS2019 在拷贝和析构的顺序上也不相同。

========================================================================================================================

C++11新特性 变参模板、完美转发(简述)的更多相关文章

  1. [转载] C++11新特性

    C++11标准发布已有一段时间了, 维基百科上有对C++11新标准的变化和C++11新特性介绍的文章. 我是一名C++程序员,非常想了解一下C++11. 英文版的维基百科看起来非常费劲,而中文版维基百 ...

  2. c++学习书籍推荐《深入理解C++11 C++11新特性解析与应用》下载

    百度云及其他网盘下载地址:点我 编辑推荐 <深入理解C++11:C++11新特性解析与应用>编辑推荐:C++标准委员会成员和IBM XL编译器中国开发团队共同撰写,权威性毋庸置疑.系统.深 ...

  3. c++ 11 线程池---完全使用c++ 11新特性

    前言: 目前网上的c++线程池资源多是使用老版本或者使用系统接口实现,使用c++ 11新特性的不多,最近研究了一下,实现一个简单版本,可实现任意任意参数函数的调用以及获得返回值. 0 前置知识 首先介 ...

  4. C++ 11学习和掌握 ——《深入理解C++ 11:C++11新特性解析和应用》读书笔记(一)

    因为偶然的机会,在图书馆看到<深入理解C++ 11:C++11新特性解析和应用>这本书,大致扫下,受益匪浅,就果断借出来,对于其中的部分内容进行详读并亲自编程测试相关代码,也就有了整理写出 ...

  5. C++11新特性之一——Lambda表达式

    C++11新特性总结可以参考:http://www.cnblogs.com/pzhfei/archive/2013/03/02/CPP_new_feature.html#section_6.8 C++ ...

  6. C++11 新特性之智能指针(shared_ptr, unique_ptr, weak_ptr)

    这是C++11新特性介绍的第五部分,涉及到智能指针的相关内容(shared_ptr, unique_ptr, weak_ptr). shared_ptr shared_ptr 基本用法 shared_ ...

  7. C++11新特性— auto 和 decltype 区别和联系

    一. auto简介 编程时候常常需要把表达式的值付给变量,需要在声明变量的时候清楚的知道变量是什么类型.然而做到这一点并非那么容易(特别是模板中),有时候根本做不到.为了解决这个问题,C++11新标准 ...

  8. c++11新特性注意点

    本文记录下一些c++11新特性需要注意的方面,供日后参考 一.auto auto可以当成“占位符”,根据右边的类型自动推导出变量的类型.需要注意的是 auto不能解决溢出的问题. auto可以与指针和 ...

  9. C++11 变长模版和完美转发实例代码

    C++11 变长模版和完美转发实例代码 #include <memory>#include <iostream>#include <vector>#include ...

随机推荐

  1. 验证rbd的缓存是否开启

    简单快速的在客户端验证rbd的cache是否开启 首先修改配置文件 在ceph.conf中添加: [client] rbd cache = true rbd cache writethrough un ...

  2. POJ2689 [质数距离] 题解

    质数距离 题目TP门 题目描述 给定两个整数L和R,你需要在闭区间[L,R]内找到距离最接近的两个相邻质数C1和C2(即C2-C1是最小的),如果存在相同距离的其他相邻质数对,则输出第一对. 同时,你 ...

  3. Java编发编程 - 线程池的认识(二)

    核心线程池的内部实现 依然参考 JDK 对线程池的支持,各个接口.相关类之间的关系:  (1)对于Executors中几个创建线程池方法底层实现: // 创建固定线程数量的线程池 public sta ...

  4. HTML5大纲算法

    什么是HTML大纲算法? 大纲算法允许用户代理(user agent)从一个web页面生成一个信息结构目录,让用户对页面有一个快速的概览.类似书籍.PDF.帮助文档等,都有一个清晰的目录结构,用户能方 ...

  5. kali 系列学习02 - 被动扫描

    被动扫描是指目标无法察觉的情况下进行信息收集,注意有经验的渗透工程师会在信息收集上花费整个测试过程一半以上的时间,信息量太大,需要自动化的信息收集工具. 一.借鉴<kali linux2 网络渗 ...

  6. 讲一讲Java的字符串常量池,看完你的思路就清晰了

    前言 很多朋友Java的字符串常量池的概念困扰了很长一段时间,最近研究了一下jvm指令码,终于对它有了大概的了解. 在展示案例前,我们需要先搞清楚一个概念,众所周知,jvm的内存模型由程序计数器.虚拟 ...

  7. 从维基百科等网站复制数据和公式到MathType里编辑

    在我们写论文的时候,经常会需要用一些实际案例以及数据,而这些数据和案例有很大一部分可以直接在网络上找到.但是有时候也会发现我们想要的内容和公式,从网页上复制粘贴后太模糊,不适合打印和投影.就需要我们将 ...

  8. 配置jdb

    目录 注:1)查看当前Linux系统是否已经安装java 1.把jdk文件的压缩包拖入虚拟机 2.找到刚刚拖拽的文件 3.在usr/local下创建jdk的文件夹 4.解压jdk的文件,并存放在刚刚创 ...

  9. ubuntu解决安装速度问题

    速度慢得原因:linux系统很多的软件源链接都是在国外服务器上,由于国内防火墙影响导致下载速度极慢,甚至超时. 解决办法一:购买梯子 这样你就可以快速的下载国外服务器的软件包了,但是你得有个可靠得梯子 ...

  10. jmeter简单的压力测试

    Jmeter是一个非常好用的压力测试工具.  Jmeter用来做轻量级的压力测试,非常合适,只需要十几分钟,就能把压力测试需要的脚本写好.相比LR来说操作简单方便,关键是免费,基于JAVA开发,所以需 ...