C++11 新特性 之 变参模板、完美转发和emplace

C++11 中的 emplace 最近读《C++ 标准库》这本书,发现C++11中大部分的容器对于添加元素除了传统的insert或者之外都提供一个新的函数叫做emplace。比如如果你想要向那么这两种方式的区别到底是什么呢?在《C++标准库》一书中没有给出解释,我查了一 下相关的资料,在此做一个总结。 阅读详情

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

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

这新特性主要是用来提升开发效率的!

下面举一个例子:

当一个容器存储一个对象时,编译器到底是如何运行的呢?需要怎么消耗性能?

我们需要定义一个类Human,实现构造函数,拷贝构造函数;私有数据成员age 和 name; 当把这样的类定义出的对象存入容器中,会发生怎么的操作呢?

这里以vector容器为例:

/*
C++11新特性 变参模板、完美转发和emplace

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

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

#include <iostream>
#include <Windows.h>
#include <string>
#include <vector>
#include <deque>
#include <list>

using namespace std;

class Human {
public:
	Human(int age, const string name) {
		this->age = age;
		this->name = name;
		cout << "调用了有参数的构造函数!" << endl;
	}

	Human(const Human& human) {
		this->age = human.age;
		this->name = human.name;
		cout << "调用了拷贝构造函数!" << endl;
	}

	void print(void) {
		cout << "年龄:" << age << " 姓名:" << name << endl;
	}

private:
	int age;
	string name;
};

int main(void) {
	vector<Human> v1;
	Human man(25, "男人");

	// 第一种
	v1.push_back(man);
	v1[0].print();

	// 第二种
	v1.push_back(Human(26, "女人"));
	v1[1].print();

	system("pause");
	return 0;
}

main函数中,我们把他分成了两种情况,
第一种是定义好对象后再存入容器中;
第二种是直接定义临时对象再存入容器中。

根据这两种情况我们运行一下:
在这里插入图片描述
怎么会调用了那么多次构造函数和拷贝构造函数呢?
下面我一行一行解释:

  1. 第一行:调用了有参构造函数
    这是定义man对象是调用的!没有问题。
    Human man(25, "男人");

  2. 第二行:调用了拷贝构造函数
    这是将man存入容器中调用的,因为存入容器中并不是把对象的引用存进去,而是把对象的值存进去,所以需要调用拷贝构造函数;且容器里的对象与外面man对象毫无瓜葛!
    v1.push_back(man);

  3. 第三行:打印结果!

  4. 第四行:调用了有参构造函数
    这是创建临时对象时调用的!
    v1.push_back(Human(26, "女人"));里面的Human(26, "女人")!

  5. 第五行:调用了拷贝构造函数

  1. 这个千万不要以为是把临时对象存进容器中调用的,这里大有玄机。
  2. 当前v1容器中已经存有一个元素,他的内存长度也就只有一个元素那么大;
  3. 那么,内存不够,他又是如何能存储第二个对象进去呢?
  4. 原因是容器自动分配了一段新的内存,可用于存储两个对象的内存;
  5. 于是乎,就先把第一个对象的拷贝到新开辟的内存中,就调用拷贝构造函数!
    如图:
    在这里插入图片描述
  1. 第六行:调用了拷贝构造函数
    内存分配好后,这个才是把第二个临时对象存入容器中所调用的拷贝构造函数!
    v1.push_back(Human(26, "女人"));
    如图:
    在这里插入图片描述

  2. 第七行:打印结果!


至此,我已经详细的解释了每行语句的特性,相信大家也懂的了。

那么,调用那么多次构造函数,如此消耗性能,这对于 “高并发” 是最忌讳的。
所以,为了解决这样的问题,C++11 新标准推出了“变参模板、完美转发和emplace”可以将这个问题完美解决!

还是上面的代码,不过使用C++11新特性:

/*
C++11新特性 变参模板、完美转发和emplace

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

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

#include <iostream>
#include <Windows.h>
#include <string>
#include <vector>
#include <deque>
#include <list>

using namespace std;

class Human {
public:
	Human(int age, const string name) {
		this->age = age;
		this->name = name;
		cout << "调用了有参数的构造函数!" << endl;
	}

	Human(const Human& human) {
		this->age = human.age;
		this->name = human.name;
		cout << "调用了拷贝构造函数!" << endl;
	}

	void print(void) {
		cout << "年龄:" << age << " 姓名:" << name << endl;
	}

private:
	int age;
	string name;
};

int main(void) {
	vector<Human> v1;

	// C++ 11 新特性
	v1.emplace_back(27, "外星人");
	v1[0].print();

	v1.emplace_back(28, "宇宙人");
	v1[1].print();

	system("pause");
	return 0;
}

使用新特性再把对象存入容器中,可以直接使用临时对象,而不用再去创建一个对象,这样也大大增加了开发效率!

运行截图:
在这里插入图片描述

哇,我的天啊,居然少调用了两次拷贝构造函数,这里面的底层原理到底是如何实现的呢???

请看我一行一行为解释。

  1. 第一行:调用了有参构造函数
    对应的是v1.emplace_back(27, "外星人");
    他是创建对象时就把它存入容器中了,所以就不用再掉用拷贝构造函数。

  2. 第二行:打印结果

  3. 第三行:调用了有参构造函数
    对应的是v1.emplace_back(28, "宇宙人");
    这里又有玄机,他是先创建临时对象,但是并没有存入容器中,因为容器的内存也是不够存储第二个对象了,所以,得再重新分配一块内存。
    然后再将临时对象存入容器的第二个位置中!!!

这点是小编的猜测,没有具体验证过!!!

如图:
在这里插入图片描述

  1. 第四行:调用了拷贝构造函数
    这里是把容器原有的元素拷贝到新开辟的内存中
    如图:
    在这里插入图片描述

  2. 第五行:打印结果


到了这里,相信大家应该都知道了C++11的新特性的作用了吧!!!

deque 和 list 也是一样的,但是他们的执行效率会比vector更高。

请看代码示例:

/*
C++11新特性 变参模板、完美转发和emplace

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

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

#include <iostream>
#include <Windows.h>
#include <string>
#include <vector>
#include <deque>
#include <list>

using namespace std;

class Human {
public:
	Human(int age, const string name) {
		this->age = age;
		this->name = name;
		cout << "调用了有参数的构造函数!" << endl;
	}

	Human(const Human& human) {
		this->age = human.age;
		this->name = human.name;
		cout << "调用了拷贝构造函数!" << endl;
	}

	void print(void) {
		cout << "年龄:" << age << " 姓名:" << name << endl;
	}

private:
	int age;
	string name;
};

int main(void) {
	vector<Human> v1;
	
	cout << "---deque---" << endl;
	deque<Human> d1;

	d1.emplace_back(25, "男人");
	d1[0].print();
	d1.emplace_back(26, "女人");
	d1[1].print();



	cout << endl << endl << "---list---" << endl;
	list<Human> list;

	list.emplace_back(25, "男人");
	list.emplace_front(26, "女人");

	system("pause");
	return 0;
}

运行截图:
在这里插入图片描述
看到了吧,他们的执行效率确实是比vector要高!!!

不懂vector容器的可以点这里;
不懂deque容器的可以点这里;
不懂list容器的可以点这里。


另外deque 和 list 容器都比vector容器多一种用法:
在第一个元素位置插入:

d1.emplace_front(21"男人");
list.emplace_front(20"女人");

此外, 他们三个共有的一个除了emplace_back外,还有一个emplace;他相当于insert插入函数。
例:
在list容器最后的位置插入

list.emplace(list.end(), 18, "灭霸");	// 相当于insert

下面是全部测试代码:

/*
C++11新特性 变参模板、完美转发和emplace

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

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

#include <iostream>
#include <Windows.h>
#include <string>
#include <vector>
#include <deque>
#include <list>

using namespace std;

class Human {
public:
	Human(int age, const string name) {
		this->age = age;
		this->name = name;
		cout << "调用了有参数的构造函数!" << endl;
	}

	Human(const Human& human) {
		this->age = human.age;
		this->name = human.name;
		cout << "调用了拷贝构造函数!" << endl;
	}

	void print(void) {
		cout << "年龄:" << age << " 姓名:" << name << endl;
	}

private:
	int age;
	string name;
};

int main(void) {
	vector<Human> v1;
	//Human man(25, "男人");

	//// 第一种
	//v1.push_back(man);
	//v1[0].print();

	//// 第二种
	//v1.push_back(Human(26, "女人"));
	//v1[1].print();

	// C++ 11 新特性
	/*v1.emplace_back(27, "外星人");
	v1[0].print();

	v1.emplace_back(28, "宇宙人");
	v1[1].print();*/


	cout << "---deque---" << endl;
	deque<Human> d1;

	d1.emplace_back(25, "男人");
	d1[0].print();
	d1.emplace_back(26, "女人");
	d1[1].print();



	cout << endl << endl << "---list---" << endl;
	list<Human> list;

	list.emplace_back(25, "男人");
	list.emplace_front(26, "女人");


	//list.emplace(list.end(), 18, "灭霸");	// 相当于insert
	

	system("pause");
	return 0;
}

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

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


博主还是一个C++萌新,如果博文里面有哪些地方是解析错误的,希望大神们能指点出来,谢谢!

嵌入式工程师成长之路(1)——元件基础(完整版) 为什么你的电路总是“玄学”故障?答案藏在这些元件里! 0欧电阻竟能引发信号反射?5V转3.3V电平匹配失败导致MCU烧毁?电容降压设计让电源“滋滋”响?——这些坑,本文全填平! 优快云硬件领域头部博主十年踩坑经验汇总,覆盖电阻、电容、电感核心难点+高频实战问题,让你从“调试地狱”直通“一次成功”! 阅读详情

相关推荐

某盾blackBox逆向——纯算

某盾blackBox逆向——纯算

Lzyydsb的博客 5891

C++11新特性之十一:emplace

emplace操作是C++11新特性,新引入的的三个成员emlace_front、empace 和 emplace_back,这些操作构造而不是拷贝元素到容器中,这些操作分别对应push_front、insert 和push_back,允许我们将元素放在容器头部、一个指定的位置和容器尾部。两者的区别当调用insert时,我们将元素类型的对象传递给insert,元素的对象被拷贝到容器中,而当我们使...

草上爬的博客 7768

从零搭建风电场:手把手教你用WAsP+WindPRO完成风资源评估全流程

本文详细介绍了从零开始搭建风电场的全流程,重点讲解如何使用WAsP和WindPRO进行风资源评估和风场布局优化。内容包括软件配置、数据采集规范、风图谱建模实战、机组选型策略以及常见问题解决方案,帮助工程师掌握风电开发的核心技术,提升项目成功率。

year5的博客 369

c/c++开发,无可避免的模板编程实践(篇十)-c++11原位构造元素(emplace)

c/c++开发,无可避免的模板编程实践(篇十)-c++11原位构造元素(emplace),介绍容器的修改器成员函数原位构造元素(emplace),并与容器旧有修改器成函数做比对,给出演示效果及源码。

技术需要分享 1397

声纹识别初学

最近开始关注声纹识别技术,发现国内做这个的确实没有几家,而且大多重点推声纹认证,用在公安司法金融领域,而我却关注文本无关的声纹识别,这里把我搜到的一点资料汇总在此. 发现njustzj001的专栏有两篇文章适合入门的我,贴下链接: 综述:  http://blog.youkuaiyun.com/xmu_jupiter/article/details/47209961 PLDA解释:  http://

u013452331的专栏 2758

手把手教你用Matlab/Simulink搭建PMSM的SMO无感FOC仿真(附相位补偿与离散化代码)

本文详细介绍了基于滑模观测器(SMO)的永磁同步电机(PMSM)无传感器FOC控制方法,通过Matlab/Simulink平台实现从理论到实践的完整流程。内容涵盖SMO核心原理、离散化处理、转子位置估算与相位补偿技术,以及双闭环控制系统搭建,为工程师提供了一套完整的无传感器控制解决方案。

weixin_27038245的博客 252

CPP emplace_bake 和 push_back 的相同和区别

cpp11 emplace_back 和 push_back的相同与区别

原来45的博客 347

Replay音频转换时samplerate缺失的解决方案指南

Replay音频转换时提示"No module named 'samplerate' This error is lazily reported, having originally occured in File"的解决方案

weixin_47445543的博客 2127

C++那些事之emplace

被人忽略的emplace返回值今天是2023年1月1日,祝福大家新年快乐~本文也是新年首更,想问大家几个问题,您能答得上来不?问题1: emplace的返回值是什么?这个看似简单,很多人都忽略的问题~问题2: 现在有一个map<string, int>,假设让你针对某个key进行插入,不存在设置0,存在更新(+1)操作,您会如何实现?是不是小样,如此简单,请看完本文~问题1的答案是st...

Francis的博客 1513

微信好友恢复全攻略(2025年3月更新)

适用于仅被拉黑场景(成功率100%)针对7天内误删场景(成功率78%)

2301_77933942的博客 1万+

【音视频 ffmpeg 学习】 RTMP推流 mp4文件

3.当RTMP协议在互联网中传输数据的时候,消息会被拆分成更小的单元,称为消息块(Chunk)。1.RTMP(实时消息传输协议)是Adobe 公司开发的一个基于TCP的应用层协议。2.RTMP协议中基本的数据单元称为消息(Message)。下载地址:http://nginx.org/download。下载 rtmp模块 到nginx 模块下。安装nginx 和 rtmp模块。(1). linux 环境准备。下载nginx安装包。使用 vcl 播放流。

weixin_45397344的博客 2273

Cpp::C++11可变参数模板和emplace系列(31)

本节也不是什么奖励课,请大家继续打起十二分的精神!一篇文章下来,其实说到底,省流:能用 emplace系列 的就尽量用,因为效率高。

tan180°的博客 1224

华为OD机试双机位C卷-组装新的数组(Py/Java/C/C++/Js/Go)

华为OD机试(机考)双机位C卷 【组装新的数组】,提供C语言、Java、C++、Python、Go、JavaScript源码实现,并提供完整思路讲解,以及在线OJ模拟做题。华为OD机试 - 组装新的数组。

qq_45776114的博客 1145

C++11新特性:变参模板、完美转发和emplace

C++11新特性:变参模板、完美转发和emplace 使得 emplace 可以接受任意参数,这样就可以适用于任意对象的构建。 《C++Primer》: 新标准引入了三个是新成员——emplace、emplace_front和emplace_back,这些操作构造而不是拷贝元素。这些操作分别对应着,insert、push_front、push_back,允许我们将元素放置在容器头部、一个指定位置之前或容器尾部。 当我们调用push或insert成员函数时,我们将元素类型的对象传递给它们,这些对象被拷贝到容

半生瓜のblog 797

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

C++11新特性 变参模板、完美转发和emplace

【代码】C++11新特性 变参模板、完美转发和emplace。

2302_79752447的博客 643

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

C++基础知识 - C++11新特性 变参模板、完美转发和emplace

C++11新特性 变参模板、完美转发和emplace 变参模板 - 使得 emplace 可以接受任意参数,这样就可以适用于任意对象的构建 完美转发 - 使得接收下来的参数 能够原样的传递给对象的构造函数,这带来另一个方便性 #include <iostream> #include <list> #include <vector> #include <deque> #include <algorithm> using namespace std

骆驼胡杨的博客 418

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

C++补充及C++11特性

explicit关键字 explicit关键字,作用时表面该构造函数是显式的不能进行隐式的转换。 什么是隐式构造,隐式构造? 举例说明: Human h1(18);//显式构造 Human h2=18;//隐式构造,当加了explicit后构造这样的对象会报错。 Human h3={18,“老王”}; 总结:加explict关键字是为了避免分歧,只使用显式构造会让人更加容易看懂代码。 ...

Jacksqh的博客 511

变参模板和完美转发(Variadic Template and Perfect Forwarding)以及一些关于vector 和 list 添加元素效率的比较

C++11 的两个强大新特性:变参模板和完美转发,以及比较 list 和 vector 在性能上的区别。

大龄工科菜鸡的cpp修行之路 1483

【C++】C++11新特性详解:可变参数模板与emplace系列的应用

大家好,我是店小二。在这篇文章中,我们将深入探讨C++11的新特性——可变参数模板和emplace系列的应用。如果在阅读过程中有不清楚的地方或发现任何错误,欢迎随时私信交流探讨。

专注于 C/C++ 后端开发,涵盖基础语法、Linux系统与网络、MySQL数据库、常见算法及项目经验。 3235

变参模板、完美转发和emplace

文章目录1 变参模板、完美转发和emplace 1 变参模板、完美转发和emplace 变参模板:使得 emplace 可以接受任意参数,这样就可以适用于任意对象的构建。 完美转发 :使得接收下来的参数能够原样的传递给对象的构造函数,这带来另一个方便性,避免构造临时对象,提高效率。 测试代码如下: #include <iostream> using namespace std; #i...

木子皿--啥都不会的菜鸟 554

C++11新特性总结

C++11新特性总结

小杰312的博客 2万+

C++11新特性(完美转发和变参模板)

变参模板 - 使得 emplace 可以接受任意参数,这样就可以适用于任意对象的构建 完美转发 - 使得接收下来的参数 能够原样的传递给对象的构造函数,这带来另一个方便性 #include<iostream> #include <vector> #include <string> using namespace std; class student { public: student() { cout << "默认构造函数被调用" <&lt.

可乐尼洛Colonnello 369

《C++进阶之C++11》【可变参数模板 + emplace接口 + 新的类功能】

摘要: 本文深入探讨了C++11中的可变参数模板及其应用,涵盖参数包的分类、基本语法与声明形式,以及关键特性。通过示例展示了参数包在sizeof...计算、递归展开、完美转发等场景的实际应用,并介绍了C++11新增的emplace接口与类功能。最后,结合可变参数模板与emplace优化容器性能,为现代C++开发提供实用技巧。

序属秋秋秋的博客 2225

【C++杂货铺】C++11新特性——可变参数模板

本篇文章介绍了 C++11 中新引入的可变模板参数,以及基于可变模板参数的 emplace 系列接口的使用原理。

春人.的博客 8050

C++11 变参模板 emplace

变参模板 - 使得 emplace 可以接受任意参数,这样就可以适用于任意对象的构建。 完美转发 - 使得接收下来的参数 能够原样的传递给对象的构造函数,这带来另一个方便性。 对象放入容器中,会调用拷贝函数。 #include <iostream> #include <vector> #include <algorithm> using namespace st...

qq_45396538的博客 213
上一篇: C++ list容器
下一篇: C/C++ 五子棋游戏
cpp_learners
博客等级 码龄7年 1526粉丝 274原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

打赏作者

cpp_learners

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

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

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

打赏作者

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

抵扣说明:

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

余额充值