C++11:移动语义与完美转发
转自
https://www.cnblogs.com/jianhui-Ethan/p/4665573.html
C++11 引入的新特性中,除了并发内存模型和相关设施,这些高帅富之外,最引人入胜且接地气的特性就要属『右值引用』了(rvalue reference)。加入右值引用的动机在于效率:减少不必要的资源拷贝。考虑下面的程序:
std::vector<string> v; v.push_back("string");
首先看push_back:
push_back(const T& x)
实际上传进来的是引用
而在push_back中构造时,使用的是construct:
void construct(T1* p,const T2& value) { new(p) T1(value); }
T1*为迭代器所指的位置,而构造的值value也是引用。T1为迭代器类型,而p为该迭代器所处的地址,也就是说construct实际上是在迭代器所属位置上,用value来构造一个T1类型的迭代器。
这里值得要注意的是,容器对其中存储元素的管理都是在堆上的(用自由存储区更精确),也就是说容器本身可能是在栈上,但它管理的元素一定是在堆上。
在回到上面的过程:
首先"string"这是一个char*指向的区域,而push_back调用的实际上里面是一个string&变量,因此首先进行隐式转换,调用string的string(const char*)这个含参的构造函数。
而这个生成的变量其实上是一个临时变量。
push_back可以看到他是传参的,因此这个临时变量直接被传进去而没有被拷贝构造。
到目前为止,使用了隐式转换,而这次隐式转换调用了含参(char*)的string的构造函数。
进入之后进入construct,而construct也是传引用,因此这里也没有调用构造。
但是在construct内部,在new时,使用了T1的含参构造,相当于在堆上利用这个临时变量构造了一个T1类型的变量
在这里调用了一次构造。
而由于vector的迭代器是原始指针,因此这里T1与T2是同一种类型(当然对其他容器就不一定是这样了)
因而调用的实际上是拷贝构造
在堆上构造完毕后,construct退栈,push_back退栈,然后这个临时变量因为离开作用域而被析构
实际上这个过程经历了一次含参构造,一次拷贝构造,一次析构
std::vector<string> v; v.push_back("string");
原文地址:https://www.cnblogs.com/lxy-xf/p/11539946.html
- python 下利用os模块创建目录以及巧妙使用if not os.path.exits()创建
- Python读取json文件,并转化为字典进行提取字段(出现索引must be int,not str)解决方案
- Python 把字典的key和value的值取出来,按照顺序存入到list中
- Go语言 如果实现http重连?
- python strip()函数 删除字符串中无空白字符或者是无用字符
- 闪回归档的简单测试(r8笔记第68天)
- sql语句查询到整个数据库的容量
- 神奇的go语言
- 备库查询导致的ORA-01110错误及修复(r8笔记第67天)
- SQL客户端DBvisualize直接导入数据出现中文乱码
- Python基础整理操作积累
- 让AI给颜值打分?应该是最公正的裁判了!
- orion的简单测试 (r8笔记第75天)
- golang ftp客户端示例 支持断点续传
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- [System.currentTimeMillis]/[Calendar.getInstance().getTimeInMillis()]/[new Date().getTime()]
- 【每日一题】32. Longest Valid Parentheses
- 面经手册 · 第3篇《HashMap核心知识,扰动函数、负载因子、扩容链表拆分深度学习(+实践验证)》
- Head First设计模式——桥接模式
- Head First设计模式——生成器模式和责任链模式
- Head First设计模式——蝇量模式和解释器模式
- 【每日一题】33. Search in Rotated Sorted Array
- 【每日一题】34. Find First and Last Position of Element in Sorted Array
- 【每日一题】35. Search Insert Position
- Head First设计模式——原型模式和访问者模式
- Java 新特性前瞻:封印类
- 每天手撕一道算法题-130. 被围绕的区域
- C#实现前向最大匹、字典树(分词、检索)
- Tomcat 中文乱码,设置UTF-8
- 从零搭建Spring Boot脚手架(4):手写Mybatis通用Mapper