C++11新特性之右值引用(&&)、移动语义(move)、完美转换(forward)
1. 右值引用
个人认为右值引用的目的主要是为了是减少内存拷贝,优化性能。
比如下面的代码:
String Fun()
{
String str = "hello world";
return str;
}
str为临时对象,然后调用Stringd的拷贝构造函数,将临时对象的值赋值给String,这种拷贝是完全没有必要的,如果堆内存很大,那么这个拷贝构造的代价会很大,带来了额外的性能损耗。
为了避免链式对象的拷贝构造,我们可以使用右值引用拷贝的方式来实现:
MyString& operator=(MyString&& other)
{
cout << "MyString& operator=(const MyString&& other)" << endl;
if (this != &other)
{
m_nLen = other.m_nLen;
m_pData = other.m_pData;
other.m_pData = NULL;
} return *this;
}
上面的代码只是进行了指针权限的转移,而没有额外的性能消耗。
1.1 使用右值引用实现MyString类
#include "stdio.h"
#include <string>
#include <iostream>
using namespace std; class MyString
{
public:
MyString() :m_pData(NULL), m_nLen()
{
cout << "MyString()" << endl;
}
MyString(const char *pStr) // 允许隐式转换
{
cout << "MyString(const char *pStr)" << endl;
m_nLen = strlen(pStr);
CopyData(pStr);
}
MyString(const MyString& other)
{
cout << "MyString(const MyString& other)" << endl;
if (!other.m_pData)
{
m_nLen = other.m_nLen;
DeleteData();
CopyData(other.m_pData);
}
}
MyString& operator=(const MyString& other)
{
cout << "MyString& operator=(const MyString& other)" << endl;
if (this != &other)
{
m_nLen = other.m_nLen;
DeleteData();
CopyData(other.m_pData);
} return *this;
} MyString(MyString&& other)
{
cout << "MyString(MyString&& other)" << endl;
m_nLen = other.m_nLen;
m_pData = other.m_pData;
other.m_pData = NULL;
} MyString& operator=(MyString&& other)
{
cout << "MyString& operator=(const MyString&& other)" << endl;
if (this != &other)
{
m_nLen = other.m_nLen;
m_pData = other.m_pData;
other.m_pData = NULL;
} return *this;
} ~MyString()
{
DeleteData();
} private:
void CopyData(const char *pData)
{
if (pData)
{
m_pData = new char[m_nLen + ];
memcpy(m_pData, pData, m_nLen);
m_pData[m_nLen] = '\0';
}
} void DeleteData()
{
if (m_pData != NULL)
{
delete[] m_pData;
m_pData = NULL;
}
} private:
char *m_pData;
size_t m_nLen;
}; MyString Fun()
{
MyString str = "hello world";
return str;
}
void main()
{
MyString str1 = "hello";
MyString str2(str1);
MyString str3 = Fun();
}

1.2 右值引用总结
C++11中引入了右值引用和移动语义,可以避免无谓的复制,提高了程序的性能,右值引用标记为T&&。
(1)左值和右值是独立于它们的类型,右值引用类型可能是左值也可能是右值
(2)auto&&或函数参数类型的自动推导的T&&是一个未定的引用类型,它可能是左值引用,也可能是右值引用,取决于初始化的值类型
(3)所有的右值引用叠加到右值引用上仍然是一个右值引用,其它引用叠加都为坐值引用,当T&&为模版参数时,输入左值,它会变为左值引用,输入右值则变为具名的右值引用
(4)编译器会将已命名的右值引用视为左值,而将未命名的右值视为右值
2. move语义
我们知道移动语义是通过右值引用来匹配临时值的,那么,普通的左值是否也能借组移动语义来优化性能呢?C++11为了解决这个问题,提供了std::move()方法来将左值转换为右值,从而方便应用移动语义。move是将对象的状态或者所有权从一个对象转移到另一个对象,只是转义,没有内存拷贝。
MyString str1 = "hello";
MyString str2(str1);
MyString str3 = Fun();
MyString str4 = move(str2);

3. forward
forward将左值转换为右值:
MyString str1 = "hello";
MyString str2(str1);
MyString str3 = Fun();
MyString str4 = move(str2);
MyString str5(forward<MyString>(str3));

4. 综合示例
#include "stdio.h"
#include<iostream> #include<vector>
using namespace std; class A
{
public:
A() :m_ptr(NULL), m_nSize(){}
A(int *ptr, int nSize)
{
m_nSize = nSize;
m_ptr = new int[nSize];
if (m_ptr)
{
memcpy(m_ptr, ptr, sizeof(sizeof(int) * nSize));
}
}
A(const A& other) // 拷贝构造函数实现深拷贝
{
m_nSize = other.m_nSize;
if (other.m_ptr)
{
delete[] m_ptr;
m_ptr = new int[m_nSize];
memcpy(m_ptr, other.m_ptr, sizeof(sizeof(int)* m_nSize));
}
else
{
m_ptr = NULL;
}
cout << "A(const int &i)" << endl;
} // 右值应用构造函数
A(A &&other)
{
m_ptr = NULL;
m_nSize = other.m_nSize;
if (other.m_ptr)
{
m_ptr = move(other.m_ptr); // 移动语义
other.m_ptr = NULL;
}
} ~A()
{
if (m_ptr)
{
delete[] m_ptr;
m_ptr = NULL;
}
} void deleteptr()
{
if (m_ptr)
{
delete[] m_ptr;
m_ptr = NULL;
}
} int *m_ptr;
int m_nSize;
}; void main()
{
int arr[] = { , , };
A a(arr, sizeof(arr)/sizeof(arr[]));
cout << "m_ptr in a Addr: 0x" << a.m_ptr << endl;
A b(a);
cout << "m_ptr in b Addr: 0x" << b.m_ptr << endl;
b.deleteptr();
A c(std::forward<A>(a)); // 完美转换
cout << "m_ptr in c Addr: 0x" << c.m_ptr << endl;
c.deleteptr(); vector<int> vect{ , , , , };
cout << "before move vect size: " << vect.size() << endl; vector<int> vect1 = move(vect);
cout << "after move vect size: " << vect.size() << endl;
cout << "new vect1 size: " << vect1.size() << endl;
}

C++11新特性之右值引用(&&)、移动语义(move)、完美转换(forward)的更多相关文章
- 透彻理解C++11新特性:右值引用、std::move、std::forward
目录 浅拷贝.深拷贝 左值.右值 右值引用类型 强转右值 std::move 重新审视右值引用 右值引用类型和右值的关系 函数参数传递 函数返还值传递 万能引用 引用折叠 完美转发 std::forw ...
- C++11新特性:右值引用和转移构造函数
问题背景 #include <iostream> using namespace std; vector<int> doubleValues (const vector< ...
- C++11的新特性:右值引用
先看代码 #include "pch.h" #include <iostream> #include <string> using namespace st ...
- C++ 11 左值,右值,左值引用,右值引用,std::move, std::foward
这篇文章要介绍的内容和标题一致,关于C++ 11中的这几个特性网上介绍的文章很多,看了一些之后想把几个比较关键的点总结记录一下,文章比较长.给出了很多代码示例,都是编译运行测试过的,希望能用这些帮助理 ...
- [转][c++11]我理解的右值引用、移动语义和完美转发
c++中引入了右值引用和移动语义,可以避免无谓的复制,提高程序性能.有点难理解,于是花时间整理一下自己的理解. 左值.右值 C++中所有的值都必然属于左值.右值二者之一.左值是指表达式结束后依然存在的 ...
- C++ 11中的右值引用以及std::move
看了很多篇文章,现在终于搞懂了C++ 中的右值以及std::move 左值和右值最重要的区别就是右值其实是一个临时的变量 在C++ 11中,也为右值引用增加了新语法,即&& 比 ...
- C++ 11 右值引用以及std::move
转载请注明出处:http://blog.csdn.net/luotuo44/article/details/46779063 新类型: int和int&是什么?都是类型.int是整数类型,in ...
- Item 25: 对右值引用使用std::move,对universal引用则使用std::forward
本文翻译自<effective modern C++>,由于水平有限,故无法保证翻译完全正确,欢迎指出错误.谢谢! 博客已经迁移到这里啦 右值引用只能绑定那些有资格被move的对象上去.如 ...
- C++11常用特性介绍——左值引用、右值引用
一.左值.右值 1)左值:可以放在赋值号左侧.可以被赋值的值:左值必须要在内存中有实体. 2)右值:必须放在赋值号右侧.取出值赋值给其它变量:右值可以在内存中也可以在CPU寄存器中. 二.引用 引用是 ...
随机推荐
- redis 笔记05 Sentinel、集群
Sentinel 1. Sentinel只是一个运行在特殊模式下的Redis服务器,它使用了和普通模式不同的命令表,所以Sentinel模式能够使用的命令和普通的Redis服务器能够使用的命令不同. ...
- C++中的config设计
配置文件读写类,它要有以下这些方法: 1. 支持读入一个指定配置文件的能力 2. 支持随时加入一个配置项的能力 3. 足够强大,能够写入各种数据结构的配置信息 C++ 里,我们要存储这样的数据就使用 ...
- DNS域名解析的配置
/etc/resolv.conf它是DNS客户机配置文件,用于设置DNS服务器的IP地址及DNS域名,还包含了主机的域名搜索顺序.该文件是由域名解析 器(resolver,一个根据主机名解析IP地址的 ...
- Linux网络IO函数以及TCP连接函数包装
标准I/O VS 网络IO 标准I/O又称为标准I/O流,从某种意义上讲是全双工的,因为程序能够在同一个流上执行输入和输出. Unix/Linux对网络的抽象是一种称为套接字的文件类型.和任何Unix ...
- 解决Vim插入模式下backspace按键无法删除字符的问题【转】
本文转载自:https://blog.csdn.net/zxy987872674/article/details/64124959 最近使用某个服务器编辑文件时,快捷键i进入插入模式后,下方不出现in ...
- JMS-activeMq发布订阅模式
上一篇对点对点模式进行总结,这一篇都发布订阅模式进行总结,代码都差不多,唯一区别就是创建队(session.createQueue(目的地))列改为创建主题(session.createTopic(目 ...
- Python连接MongoDB操作
1.安装PyMongo 注意:请勿安装“bson”软件包. PyMongo配有自己的bson包; 执行“pip install bson”或“easy_install bson”则会安装与PyMong ...
- java8 日期处理
这两周写业务逻辑,总会有各种日期操作,但是又记不住API,就是记不住API啊 这篇博客不错,记下来 https://lw900925.github.io/java/java8-newtime-api. ...
- Pro C/C++ 编程中值得注意的问题
1.宿主字符串存储Oracle自动补零问题. EXEC SQL BEGIN DECLARE SECTION; unsigned char liId[25]; EXEC SQL END DECLARE ...
- Java Maven项目使用CXF插件生成WebService代理
CXF生成代理类插件名称:cxf-codegen-plugin 实现功能: 指定代理类所在的包 生成soapheader 操作: eclipse中run as -> maven build -& ...